﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область СлужебныеПроцедурыИФункции

// Параметры:
//  Текст - Строка 
//  ОжидаемыйВид - ПеречислениеСсылка.ТипыКонтактнойИнформации, Неопределено
//  РезультатПреобразования - Структура, Неопределено
//  НастройкиКонвертации - см. УправлениеКонтактнойИнформацией.НастройкиКонвертацииКонтактнойИнформации
// 
// Возвращаемое значение:
//   см. XDTOПакет.КонтактнаяИнформация.КонтактнаяИнформация
//
Функция КонтактнаяИнформацияИзXML(Знач Текст, Знач ОжидаемыйВид = Неопределено, РезультатПреобразования = Неопределено, НастройкиКонвертации = Неопределено) Экспорт
	
	ОжидаемыйТип = УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ТипВидаКонтактнойИнформации(ОжидаемыйВид);
	
	Если РезультатПреобразования = Неопределено Или ТипЗнч(РезультатПреобразования) <> Тип("Структура") Тогда
		РезультатПреобразования = Новый Структура;
	КонецЕсли;
	РезультатПреобразования.Вставить("СведенияИсправлены", Ложь);
	
	Если НастройкиКонвертации = Неопределено Тогда
		НастройкиКонвертации = УправлениеКонтактнойИнформацией.НастройкиКонвертацииКонтактнойИнформации();
	КонецЕсли;
	
	Представление                       = НастройкиКонвертации.Представление;
	ВосстанавливатьКонтактнуюИнформацию = НастройкиКонвертации.ВосстанавливатьКонтактнуюИнформацию;
	
	ПеречислениеАдрес                 = Перечисления.ТипыКонтактнойИнформации.Адрес;
	ПеречислениеАдресЭлектроннойПочты = Перечисления.ТипыКонтактнойИнформации.АдресЭлектроннойПочты;
	ПеречислениеSkype                 = Перечисления.ТипыКонтактнойИнформации.Skype;
	ПеречислениеВебСтраница           = Перечисления.ТипыКонтактнойИнформации.ВебСтраница;
	ПеречислениеТелефон               = Перечисления.ТипыКонтактнойИнформации.Телефон;
	ПеречислениеФакс                  = Перечисления.ТипыКонтактнойИнформации.Факс;
	ПеречислениеДругое                = Перечисления.ТипыКонтактнойИнформации.Другое;
	
	ПространствоИмен = ПространствоИмен();
	
	Если УправлениеКонтактнойИнформациейКлиентСервер.ЭтоКонтактнаяИнформацияВXML(Текст) Тогда
		ЧтениеXML = Новый ЧтениеXML;
		
		Если УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ДоступныМодулиРаботаСАдресами()  Тогда
			МодульРаботаСАдресами = ОбщегоНазначения.ОбщийМодуль("РаботаСАдресами");
			Текст = МодульРаботаСАдресами.ПередЧтениемXDTOКонтактнаяИнформация(Текст);
		КонецЕсли;
		
		ЧтениеXML.УстановитьСтроку(Текст);
		
		ТекстОшибки = Неопределено;
		
		НеобходимоВосстановитьКонтактнуюИнформацию = Ложь;
		
		Попытка
			
			Результат = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML, ФабрикаXDTO.Тип(ПространствоИмен, "КонтактнаяИнформация")); // см. XDTOПакет.КонтактнаяИнформация.КонтактнаяИнформация
			
			Если ОжидаемыйТип = Перечисления.ТипыКонтактнойИнформации.Адрес И КонтактнаяИнформацияXDTOПустая(Результат) Тогда
					НеобходимоВосстановитьКонтактнуюИнформацию = Истина;
			ИначеЕсли ПустаяСтрока(Результат.Представление) Тогда
				Результат.Представление = УправлениеКонтактнойИнформацией.ПредставлениеКонтактнойИнформации(Результат, ОжидаемыйВид);
			КонецЕсли;
			
		Исключение
			
			НеобходимоВосстановитьКонтактнуюИнформацию = Истина;
			
		КонецПопытки;
		
		Если ВосстанавливатьКонтактнуюИнформацию И НеобходимоВосстановитьКонтактнуюИнформацию Тогда
			
			ОписаниеПричиныОшибки = НСтр("ru = 'Сведения контактной информации были восстановлены после сбоя.'");
			Если ЗначениеЗаполнено(Представление) Тогда
				Результат = КонтактнаяИнформацияXDTOПоПредставлению(Представление, ОжидаемыйВид);
				Если СтрСравнить(Результат.Представление, Представление) <> 0  Тогда
					ТекстОшибки = ОписаниеПричиныОшибки;
					РезультатПреобразования.Вставить("ТекстОшибки", ТекстОшибки);
				КонецЕсли;
				
			КонецЕсли;
			
			// Некорректный формат XML
			ЗаписьЖурналаРегистрации(УправлениеКонтактнойИнформациейСлужебный.СобытиеЖурналаРегистрации(),
				УровеньЖурналаРегистрации.Предупреждение, , Текст, ОписаниеПричиныОшибки + Символы.ПС
					+ ИнформацияОбОшибке().Описание);
				
			РезультатПреобразования.Вставить("СведенияИсправлены", Истина);
		КонецЕсли;
		
		Если ТекстОшибки = Неопределено И ОжидаемыйТип <> Неопределено Тогда
			
			Если Результат = Неопределено Тогда
				ТекстОшибки = СтрЗаменить(НСтр("ru = 'Сведения контактной информации %ОжидаемыйВид% были повреждены или некорректно заполнены.'"),
					"%ОжидаемыйВид%", Строка(ОжидаемыйВид));
			Иначе
				// Контролируем соответствие типов.
				НайденТип = ?(Результат.Состав = Неопределено, Неопределено, Результат.Состав.Тип());
				
				ШаблонСообщения = СтрЗаменить(НСтр("ru = 'Сведения %1 контактной информации %ОжидаемыйВид% были повреждены или некорректно заполнены.'"),
					"%ОжидаемыйВид%", Строка(ОжидаемыйВид));
				Если ОжидаемыйТип = ПеречислениеАдрес И НайденТип <> ФабрикаXDTO.Тип(ПространствоИмен, "Адрес") Тогда
					ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонСообщения, НСтр("ru = 'об адресе'"));
				ИначеЕсли ОжидаемыйТип = ПеречислениеАдресЭлектроннойПочты И НайденТип <> ФабрикаXDTO.Тип(ПространствоИмен, "ЭлектроннаяПочта") Тогда
					ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонСообщения, НСтр("ru = 'электронной почты'"));
				ИначеЕсли ОжидаемыйТип = ПеречислениеВебСтраница И НайденТип <> ФабрикаXDTO.Тип(ПространствоИмен, "ВебСайт") Тогда
					ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонСообщения, НСтр("ru = 'веб-страницы'"));
				ИначеЕсли ОжидаемыйТип = ПеречислениеТелефон И НайденТип <> ФабрикаXDTO.Тип(ПространствоИмен, "НомерТелефона") Тогда
					ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонСообщения, НСтр("ru = 'о номере телефона'"));
				ИначеЕсли ОжидаемыйТип = ПеречислениеФакс И НайденТип <> ФабрикаXDTO.Тип(ПространствоИмен, "НомерФакса") Тогда
					ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонСообщения, НСтр("ru = 'о номере факса'"));
				ИначеЕсли ОжидаемыйТип = ПеречислениеSkype И НайденТип <> ФабрикаXDTO.Тип(ПространствоИмен, "Skype") Тогда
					ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонСообщения, НСтр("ru = 'о логине Skype'"));
				ИначеЕсли ОжидаемыйТип = ПеречислениеДругое И НайденТип <> ФабрикаXDTO.Тип(ПространствоИмен, "Прочее") Тогда
					ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонСообщения, НСтр("ru = 'о дополнительной'"));
				КонецЕсли;
			КонецЕсли;
		КонецЕсли;
		
		Если ТекстОшибки = Неопределено Тогда
			// Успешно прочитано
			Возврат Результат;
		КонецЕсли;
		
		РезультатПреобразования.Вставить("ТекстОшибки", ТекстОшибки);
		
		// Будет возвращен пустой объект.
		Текст = "";
	КонецЕсли;
	
	Если ТипЗнч(Текст) = Тип("СписокЗначений") Тогда
		Представление = "";
		ЭтоНовый = Текст.Количество() = 0;
	ИначеЕсли ПустаяСтрока(Представление) И СтрЧислоСтрок(Текст) = 1 Тогда
		Представление = Строка(Текст);
		ЭтоНовый = ПустаяСтрока(Текст);
	Иначе
		ЭтоНовый = Ложь;
	КонецЕсли;
	
	Результат = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "КонтактнаяИнформация")); // см. XDTOПакет.КонтактнаяИнформация
	
	// Разбор
	Если ОжидаемыйТип = ПеречислениеАдрес Тогда
		Если ЭтоНовый Тогда
			Результат.Состав = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "Адрес"));
		Иначе
			Результат = АдресXMLВXDTO(Текст, Представление, ОжидаемыйТип);
		КонецЕсли;
		
	ИначеЕсли ОжидаемыйТип = ПеречислениеТелефон Тогда
		Если ЭтоНовый Тогда
			Результат.Состав = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "НомерТелефона"));
		Иначе
			Результат = ДесериализацияТелефона(Текст, Представление, ОжидаемыйТип)
		КонецЕсли;
		
	ИначеЕсли ОжидаемыйТип = ПеречислениеФакс Тогда
		Если ЭтоНовый Тогда
			Результат.Состав = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "НомерФакса"));
		Иначе
			Результат = ДесериализацияФакса(Текст, Представление, ОжидаемыйТип)
		КонецЕсли;
		
	ИначеЕсли ОжидаемыйТип = ПеречислениеАдресЭлектроннойПочты Тогда
		Если ЭтоНовый Тогда
			Результат.Состав = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "ЭлектроннаяПочта"));
		Иначе
			Результат = ДесериализацияПрочейКонтактнойИнформации(Текст, Представление, ОжидаемыйТип)
		КонецЕсли;
	ИначеЕсли ОжидаемыйТип = ПеречислениеSkype Тогда
		Если ЭтоНовый Тогда
			Результат.Состав = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "Skype"));
		Иначе
			Результат = ДесериализацияПрочейКонтактнойИнформации(Текст, Представление, ОжидаемыйТип)
		КонецЕсли;
	ИначеЕсли ОжидаемыйТип = ПеречислениеВебСтраница Тогда
		Если ЭтоНовый Тогда
			Результат.Состав = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "ВебСайт"));
		Иначе
			Результат = ДесериализацияПрочейКонтактнойИнформации(Текст, Представление, ОжидаемыйТип)
		КонецЕсли;
		
	ИначеЕсли ОжидаемыйТип = ПеречислениеДругое Тогда
		Если ЭтоНовый Тогда
			Результат.Состав = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "Прочее"));
		Иначе
			Результат = ДесериализацияПрочейКонтактнойИнформации(Текст, Представление, ОжидаемыйТип)
		КонецЕсли;
		
	Иначе
		ТекстОшибки = НСтр("ru = 'Сведения о виде контактной информации %1 были повреждены или некорректно заполнены,
								|т.к. обязательное поле тип не заполнено.'");
		ТекстОшибки =  СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстОшибки, ?(ЗначениеЗаполнено(ОжидаемыйВид), """" + ОжидаемыйВид.Наименование + """", ""));
		РезультатПреобразования.Вставить("ТекстОшибки", ТекстОшибки);
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Функция КонтактнаяИнформацияИзJSONВXML(Знач КонтактнаяИнформация, ОжидаемыйТип = Неопределено) Экспорт
	
	Если УправлениеКонтактнойИнформациейКлиентСервер.ЭтоКонтактнаяИнформацияВJSON(КонтактнаяИнформация) Тогда
		КонтактнаяИнформация = УправлениеКонтактнойИнформациейСлужебный.JSONВКонтактнуюИнформациюПоПолям(КонтактнаяИнформация, ОжидаемыйТип);
	КонецЕсли;
	
	Если ОжидаемыйТип = Неопределено Тогда
		
		Если ТипЗнч(КонтактнаяИнформация) = Тип("Структура") И КонтактнаяИнформация.Свойство("type") Тогда
			
			ОжидаемыйТип = Перечисления.ТипыКонтактнойИнформации[КонтактнаяИнформация.type];
			
		ИначеЕсли УправлениеКонтактнойИнформациейКлиентСервер.ЭтоКонтактнаяИнформацияВXML(КонтактнаяИнформация) Тогда
			КонтактнаяИнформацияXML = ПривестиКонтактнуюИнформациюXML(КонтактнаяИнформация);
			ОжидаемыйТип = КонтактнаяИнформацияXML.ТипКонтактнойИнформации;
		Иначе
			ТекстОшибки = НСтр("ru = 'Ошибка конвертации контактной информации из формата JSON в XML.'");
			ЗаписьЖурналаРегистрации(ОбновлениеИнформационнойБазы.СобытиеЖурналаРегистрации(), 
				УровеньЖурналаРегистрации.Ошибка,,,
				ТекстОшибки + Символы.ПС + Строка(КонтактнаяИнформация));
			ВызватьИсключение НСтр("ru = 'Не удалось определить тип контактной информации. Подробнее см. в журнале регистрации.'");
		КонецЕсли;
		
	КонецЕсли;
	
	ПространствоИмен = ПространствоИмен();

	ЭтоНовый = ПустаяСтрока(КонтактнаяИнформация);
	Представление = "";
	
	Результат = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "КонтактнаяИнформация"));
	
	// Разбор
	Если ОжидаемыйТип = Перечисления.ТипыКонтактнойИнформации.Адрес Тогда
		Если ЭтоНовый Тогда
			Результат.Состав = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "Адрес"));
		Иначе
			Результат = КонвертироватьАдресИзJSONВXML(КонтактнаяИнформация, Представление, ОжидаемыйТип);
		КонецЕсли;
		
	ИначеЕсли ОжидаемыйТип = Перечисления.ТипыКонтактнойИнформации.Телефон Тогда
		Если ЭтоНовый Тогда
			Результат.Состав = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "НомерТелефона"));
		Иначе
			Результат = КонвертироватьТелефонФаксИзJSONВXML(КонтактнаяИнформация, Представление, ОжидаемыйТип)
		КонецЕсли;
		
	ИначеЕсли ОжидаемыйТип = Перечисления.ТипыКонтактнойИнформации.Факс Тогда
		Если ЭтоНовый Тогда
			Результат.Состав = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "НомерФакса"));
		Иначе
			Результат = КонвертироватьТелефонФаксИзJSONВXML(КонтактнаяИнформация, Представление, ОжидаемыйТип)
		КонецЕсли;
		
	ИначеЕсли ОжидаемыйТип = Перечисления.ТипыКонтактнойИнформации.АдресЭлектроннойПочты Тогда
		Если ЭтоНовый Тогда
			Результат.Состав = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "ЭлектроннаяПочта"));
		Иначе
			Результат = КонвертироватьПрочуюКонтактнуюИнформациюИзJSONВXML(КонтактнаяИнформация, Представление, ОжидаемыйТип)
		КонецЕсли;
	ИначеЕсли ОжидаемыйТип = Перечисления.ТипыКонтактнойИнформации.Skype Тогда
		Если ЭтоНовый Тогда
			Результат.Состав = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "Skype"));
		Иначе
			Результат = КонвертироватьПрочуюКонтактнуюИнформациюИзJSONВXML(КонтактнаяИнформация, Представление, ОжидаемыйТип)
		КонецЕсли;
	ИначеЕсли ОжидаемыйТип = Перечисления.ТипыКонтактнойИнформации.ВебСтраница Тогда
		Если ЭтоНовый Тогда
			Результат.Состав = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "ВебСайт"));
		Иначе
			Результат = КонвертироватьПрочуюКонтактнуюИнформациюИзJSONВXML(КонтактнаяИнформация, Представление, ОжидаемыйТип)
		КонецЕсли;
		
	ИначеЕсли ОжидаемыйТип = Перечисления.ТипыКонтактнойИнформации.Другое Тогда
		Если ЭтоНовый Тогда
			Результат.Состав = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "Прочее"));
		Иначе
			Результат = КонвертироватьПрочуюКонтактнуюИнформациюИзJSONВXML(КонтактнаяИнформация, Представление, ОжидаемыйТип)
		КонецЕсли;
		
	Иначе
		ТекстОшибки = НСтр("ru = 'Сведения о виде контактной информации %1 были повреждены или некорректно заполнены,
								|т.к. обязательное поле тип не заполнено.'");
		ТекстОшибки =  СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстОшибки, ?(ЗначениеЗаполнено(ОжидаемыйТип), """" + СокрЛП(ОжидаемыйТип) + """", ""));
	КонецЕсли;
	
	Возврат КонтактнаяИнформацияXDTOВXML(Результат);
	
КонецФункции

Функция КонвертироватьАдресИзJSONВXML(Знач ЗначенияПолей, Знач Представление, Знач ОжидаемыйТип = Неопределено)
	
	Если УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ДоступныМодулиРаботаСАдресами() Тогда
		МодульРаботаСАдресами = ОбщегоНазначения.ОбщийМодуль("РаботаСАдресами");
		Возврат МодульРаботаСАдресами.КонвертироватьАдресИзJSONВXML(ЗначенияПолей, Представление, ОжидаемыйТип);
	КонецЕсли;
	
	// Старый формат через разделитель строк и равенство.
	ПространствоИмен = ПространствоИмен();
	
	Результат = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "КонтактнаяИнформация")); 
	Результат.Состав      = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "Адрес"));
	
	// Общий состав
	Адрес = Результат.Состав; // см. XDTOПакет.КонтактнаяИнформация.Адрес
	
	ПолеПредставления      = "";
	
	Для Каждого ЭлементСписка Из ЗначенияПолей Цикл
		
		Если ПустаяСтрока(ЭлементСписка.Значение) Тогда
			Продолжить;
		КонецЕсли;
		
		ИмяПоля = ВРег(ЭлементСписка.Ключ);
		
		Если ИмяПоля = "COMMENT" Тогда
			Комментарий = СокрЛП(ЭлементСписка.Значение);
			Если ЗначениеЗаполнено(Комментарий) Тогда
				Результат.Комментарий = Комментарий;
			КонецЕсли;
			
		ИначеЕсли ИмяПоля = "COUNTRY" Тогда
			Адрес.Страна = Строка(ЭлементСписка.Значение);
			
		ИначеЕсли ИмяПоля = "VALUE" Тогда
			ПолеПредставления = СокрЛП(ЭлементСписка.Значение);
			
		КонецЕсли;
		
	КонецЦикла;
	
	// Представление с приоритетами.
	Если Не ПустаяСтрока(Представление) Тогда
		Результат.Представление = Представление;
	Иначе
		Результат.Представление = ПолеПредставления;
	КонецЕсли;
	
	Адрес.Состав = Результат.Представление;
	
	Возврат Результат;
КонецФункции

Функция КонвертироватьТелефонФаксИзJSONВXML(ЗначенияПолей, Представление = "", ОжидаемыйТип = Неопределено)
	
	Если УправлениеКонтактнойИнформациейКлиентСервер.ЭтоКонтактнаяИнформацияВXML(ЗначенияПолей) Тогда
		// Общий формат контактной информации.
		Возврат КонтактнаяИнформацияИзXML(ЗначенияПолей, ОжидаемыйТип);
	КонецЕсли;
	
	ПространствоИмен = ПространствоИмен();
	
	Если ОжидаемыйТип = Неопределено Или ОжидаемыйТип = Перечисления.ТипыКонтактнойИнформации.Телефон Тогда
		Данные = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "НомерТелефона"));
	ИначеЕсли ОжидаемыйТип = Перечисления.ТипыКонтактнойИнформации.Факс Тогда
		Данные = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "НомерФакса"));
	Иначе
		ВызватьИсключение НСтр("ru = 'Ошибка преобразования контактной информации, ожидается телефон или факс.'");
	КонецЕсли;
	
	Результат = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "КонтактнаяИнформация"));
	Результат.Состав        = Данные;
	
	ПолеПредставления = "";
	Для Каждого ЗначениеПоля Из ЗначенияПолей Цикл
		Поле = ВРег(ЗначениеПоля.Ключ);
		
		Если Поле = "COUNTRYCODE" Тогда
			Данные.КодСтраны = ЗначениеПоля.Значение;
			
		ИначеЕсли Поле = "AREACODE" Тогда
			Данные.КодГорода = ЗначениеПоля.Значение;
			
		ИначеЕсли Поле = "NUMBER" Тогда
			Данные.Номер = ЗначениеПоля.Значение;
			
		ИначеЕсли Поле = "EXTNUMBER" Тогда
			Данные.Добавочный = ЗначениеПоля.Значение;
			
		ИначеЕсли Поле = "VALUE" Тогда
			ПолеПредставления = СокрЛП(ЗначениеПоля.Значение);
			
		ИначеЕсли Поле = "COMMENT" Тогда
			Комментарий = СокрЛП(ЗначениеПоля.Значение);
			Если ЗначениеЗаполнено(Комментарий) Тогда
				Результат.Комментарий = Комментарий;
			КонецЕсли;
			
		КонецЕсли;
		
	КонецЦикла;
	
	// Представление с приоритетами.
	Если Не ПустаяСтрока(Представление) Тогда
		Результат.Представление = Представление;
	ИначеЕсли ЗначениеЗаполнено(ПолеПредставления) Тогда
		Результат.Представление = ПолеПредставления;
	Иначе
		Результат.Представление = УправлениеКонтактнойИнформациейСлужебный.ПредставлениеТелефона(Данные);
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Функция КонвертироватьПрочуюКонтактнуюИнформациюИзJSONВXML(ЗначенияПолей, Знач Представление = "", ОжидаемыйТип = Неопределено)
	
	Если УправлениеКонтактнойИнформациейКлиентСервер.ЭтоКонтактнаяИнформацияВXML(ЗначенияПолей) Тогда
		// Общий формат контактной информации.
		Возврат КонтактнаяИнформацияИзXML(ЗначенияПолей, ОжидаемыйТип);
	КонецЕсли;
	
	ПространствоИмен = ПространствоИмен();
	Результат = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "КонтактнаяИнформация"));
	
	Если ПустаяСтрока(Представление) И ЗначенияПолей.Свойство("Value") И ЗначениеЗаполнено(ЗначенияПолей.Value) Тогда
		Представление = ЗначенияПолей.Value;
	КонецЕсли;
	
	Результат.Представление = Представление;
	
	Если ОжидаемыйТип = Перечисления.ТипыКонтактнойИнформации.АдресЭлектроннойПочты Тогда
		Результат.Состав = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "ЭлектроннаяПочта"));
		
	ИначеЕсли ОжидаемыйТип = Перечисления.ТипыКонтактнойИнформации.ВебСтраница Тогда
		Результат.Состав = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "ВебСайт"));
		
	ИначеЕсли ОжидаемыйТип = Перечисления.ТипыКонтактнойИнформации.Skype Тогда
		Результат.Состав = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "Skype"));
		
	ИначеЕсли ОжидаемыйТип = Перечисления.ТипыКонтактнойИнформации.Другое Тогда
		Результат.Состав = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "Прочее"));
		
	ИначеЕсли ОжидаемыйТип <> Неопределено Тогда
		ВызватьИсключение НСтр("ru = 'Ошибка десериализации контактной информации, ожидается другой тип'");
		
	КонецЕсли;
	
	Результат.Состав.Значение = Представление;
	
	Комментарий = "";
	Если ЗначенияПолей.Свойство("Comment") И ЗначениеЗаполнено(ЗначенияПолей.Comment) Тогда
		Комментарий = СокрЛП(ЗначенияПолей.Comment);
		Если ЗначениеЗаполнено(Комментарий) Тогда
			Результат.Комментарий = Комментарий;
		КонецЕсли;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Функция ДесериализацияТелефонаФакса(ЗначенияПолей, Представление = "", ОжидаемыйТип = Неопределено)
	
	Если УправлениеКонтактнойИнформациейКлиентСервер.ЭтоКонтактнаяИнформацияВXML(ЗначенияПолей) Тогда
		// Общий формат контактной информации.
		Возврат КонтактнаяИнформацияИзXML(ЗначенияПолей, ОжидаемыйТип);
	КонецЕсли;
	
	ПространствоИмен = ПространствоИмен();
	
	Если ОжидаемыйТип = Неопределено Или ОжидаемыйТип = Перечисления.ТипыКонтактнойИнформации.Телефон Тогда
		Данные = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "НомерТелефона"));
	ИначеЕсли ОжидаемыйТип = Перечисления.ТипыКонтактнойИнформации.Факс Тогда
		Данные = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "НомерФакса"));
	Иначе
		ВызватьИсключение НСтр("ru = 'Ошибка десериализации контактной информации, ожидается телефон или факс.'");
	КонецЕсли;
	
	Результат = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "КонтактнаяИнформация"));
	Результат.Состав        = Данные;
	
	// Из пар ключ-значение
	СписокЗначенийПолей = Неопределено;
	Если ТипЗнч(ЗначенияПолей)=Тип("СписокЗначений") Тогда
		СписокЗначенийПолей = ЗначенияПолей;
	ИначеЕсли Не ПустаяСтрока(ЗначенияПолей) Тогда
		СписокЗначенийПолей = УправлениеКонтактнойИнформациейСлужебный.ПреобразоватьСтрокуВСписокПолей(ЗначенияПолей);
	КонецЕсли;
	
	ПолеПредставления = "";
	Если СписокЗначенийПолей <> Неопределено Тогда
		Для Каждого ЗначениеПоля Из СписокЗначенийПолей Цикл
			Поле = ВРег(ЗначениеПоля.Представление);
			
			Если Поле = "КОДСТРАНЫ" Тогда
				Данные.КодСтраны = ЗначениеПоля.Значение;
				
			ИначеЕсли Поле = "КОДГОРОДА" Тогда
				Данные.КодГорода = ЗначениеПоля.Значение;
				
			ИначеЕсли Поле = "НОМЕРТЕЛЕФОНА" Тогда
				Данные.Номер = ЗначениеПоля.Значение;
				
			ИначеЕсли Поле = "ДОБАВОЧНЫЙ" Тогда
				Данные.Добавочный = ЗначениеПоля.Значение;
				
			ИначеЕсли Поле = "ПРЕДСТАВЛЕНИЕ" Тогда
				ПолеПредставления = СокрЛП(ЗначениеПоля.Значение);
				
			КонецЕсли;
			
		КонецЦикла;
		
		// Представление с приоритетами.
		Если Не ПустаяСтрока(Представление) Тогда
			Результат.Представление = Представление;
		ИначеЕсли ЗначениеЗаполнено(ПолеПредставления) Тогда
			Результат.Представление = ПолеПредставления;
		Иначе
			Результат.Представление = УправлениеКонтактнойИнформациейСлужебный.ПредставлениеТелефона(Данные);
		КонецЕсли;
		
		Возврат Результат;
	КонецЕсли;
	
	// Разбираем из представления.
	
	// Группы цифр, разделенные символами - не цифрами: страна, город, номер, добавочный. 
	// Добавочный включает в себя непробельные символы слева и справа.
	Позиция = 1;
	Данные.КодСтраны  = УправлениеКонтактнойИнформациейСлужебный.НайтиПодстрокуЦифр(Представление, Позиция);
	НачалоГорода = Позиция;
	
	Данные.КодГорода  = УправлениеКонтактнойИнформациейСлужебный.НайтиПодстрокуЦифр(Представление, Позиция);
	Данные.Номер      = УправлениеКонтактнойИнформациейСлужебный.НайтиПодстрокуЦифр(Представление, Позиция, " -");
	
	Добавочный = СокрЛП(Сред(Представление, Позиция));
	Если СтрНачинаетсяС(Добавочный, ",") Тогда
		Добавочный = СокрЛ(Сред(Добавочный, 2));
	КонецЕсли;
	Если СтрНачинаетсяС(ВРег(Добавочный), "ДОБ") Тогда
		Добавочный = СокрЛ(Сред(Добавочный, СтрДлина("ДОБ") + 1));
	КонецЕсли;
	Если ВРег(Лев(Добавочный, 1 ))= "." Тогда
		Добавочный = СокрЛ(Сред(Добавочный, 2));
	КонецЕсли;
	Данные.Добавочный = СокрЛП(Добавочный);
	
	// Корректируем возможные ошибки.
	Если ПустаяСтрока(Данные.Номер) Тогда
		Если СтрНачинаетсяС(СокрЛ(Представление), "+") Тогда
			// Была попытка явно указать код страны, оставляем страну в покое.
			Данные.КодГорода  = "";
			Данные.Номер      = УправлениеКонтактнойИнформациейСлужебный.СократитьНеЦифры(Сред(Представление, НачалоГорода));
			Данные.Добавочный = "";
		Иначе
			Данные.КодСтраны  = "";
			Данные.КодГорода  = "";
			Данные.Номер      = Представление;
			Данные.Добавочный = "";
		КонецЕсли;
	КонецЕсли;
	
	Результат.Представление = Представление;
	Возврат Результат;
КонецФункции

Функция ДесериализацияТелефона(ЗначенияПолей, Представление = "", ОжидаемыйТип = Неопределено) Экспорт
	Возврат ДесериализацияТелефонаФакса(ЗначенияПолей, Представление, ОжидаемыйТип);
КонецФункции

Функция ДесериализацияФакса(ЗначенияПолей, Представление = "", ОжидаемыйТип = Неопределено) Экспорт
	Возврат ДесериализацияТелефонаФакса(ЗначенияПолей, Представление, ОжидаемыйТип);
КонецФункции

Функция ДесериализацияПрочейКонтактнойИнформации(ЗначенияПолей, Представление = "", ОжидаемыйТип = Неопределено)
	
	Если УправлениеКонтактнойИнформациейКлиентСервер.ЭтоКонтактнаяИнформацияВXML(ЗначенияПолей) Тогда
		// Общий формат контактной информации.
		Возврат КонтактнаяИнформацияИзXML(ЗначенияПолей, ОжидаемыйТип);
	КонецЕсли;
	
	ПространствоИмен = ПространствоИмен();
	Результат = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "КонтактнаяИнформация"));
	Результат.Представление = Представление;
	
	Если ОжидаемыйТип = Перечисления.ТипыКонтактнойИнформации.АдресЭлектроннойПочты Тогда
		Результат.Состав = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "ЭлектроннаяПочта"));
		
	ИначеЕсли ОжидаемыйТип = Перечисления.ТипыКонтактнойИнформации.ВебСтраница Тогда
		Результат.Состав = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "ВебСайт"));
		
	ИначеЕсли ОжидаемыйТип = Перечисления.ТипыКонтактнойИнформации.Skype Тогда
		Результат.Состав = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "Skype"));
		
	ИначеЕсли ОжидаемыйТип = Перечисления.ТипыКонтактнойИнформации.Другое Тогда
		Результат.Состав = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "Прочее"));
		
	ИначеЕсли ОжидаемыйТип <> Неопределено Тогда
		ВызватьИсключение НСтр("ru = 'Ошибка десериализации контактной информации, ожидается другой тип'");
		
	КонецЕсли;
	
	Результат.Состав.Значение = Представление;
	
	Возврат Результат;
	
КонецФункции

Функция КонтактнаяИнформацияXDTOПоПредставлению(Текст, ОжидаемыйВид) Экспорт
	
	ОжидаемыйТип = УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ТипВидаКонтактнойИнформации(ОжидаемыйВид);
	Если ОжидаемыйТип = Перечисления.ТипыКонтактнойИнформации.Адрес Тогда
		Возврат АдресXMLВXDTO("", Текст, ОжидаемыйТип);
		
	ИначеЕсли ОжидаемыйТип = Перечисления.ТипыКонтактнойИнформации.АдресЭлектроннойПочты 
		Или ОжидаемыйТип = Перечисления.ТипыКонтактнойИнформации.ВебСтраница
		Или ОжидаемыйТип = Перечисления.ТипыКонтактнойИнформации.Skype
		Или ОжидаемыйТип = Перечисления.ТипыКонтактнойИнформации.Другое Тогда
		Возврат ДесериализацияПрочейКонтактнойИнформации("", Текст, ОжидаемыйТип);
		
	ИначеЕсли ОжидаемыйТип = Перечисления.ТипыКонтактнойИнформации.Телефон Тогда
		Возврат ДесериализацияТелефона("", Текст, ОжидаемыйТип);

	ИначеЕсли ОжидаемыйТип = Перечисления.ТипыКонтактнойИнформации.Факс Тогда
		Возврат ДесериализацияФакса("", Текст, ОжидаемыйТип);
	КонецЕсли;
	
	Возврат Неопределено;

КонецФункции

Процедура УстановитьКомментарийКонтактнойИнформации(КонтактнаяИнформация, Знач Комментарий) Экспорт
	
	ЭтоСтрока = ТипЗнч(КонтактнаяИнформация) = Тип("Строка");
	Если ЭтоСтрока И Не УправлениеКонтактнойИнформациейКлиентСервер.ЭтоКонтактнаяИнформацияВXML(КонтактнаяИнформация) Тогда
		// Предыдущий формат значений полей, комментарий отсутствует.
		Возврат;
	КонецЕсли;
	
	ОбъектXDTO = ?(ЭтоСтрока, КонтактнаяИнформацияИзXML(КонтактнаяИнформация), КонтактнаяИнформация);
	ОбъектXDTO.Комментарий = Комментарий;
	Если ЭтоСтрока Тогда
		КонтактнаяИнформация = КонтактнаяИнформацияXDTOВXML(ОбъектXDTO);
	КонецЕсли;
	
КонецПроцедуры

Функция ЗаполнитьРеквизитыТабличнойЧастиДляВебСтраницы(Источник) Экспорт
	
	АдресСтраницы = Источник.Состав;
	ПространствоИмен = ПространствоИмен();
	Если АдресСтраницы <> Неопределено И АдресСтраницы.Тип() = ФабрикаXDTO.Тип(ПространствоИмен, "ВебСайт") Тогда
		АдресСтрокой = АдресСтраницы.Значение;
	КонецЕсли;
	
	Возврат АдресСтрокой;
	
КонецФункции

Функция АдресXMLВXDTO(Знач ЗначенияПолей, Знач Представление = "", Знач ОжидаемыйТип = Неопределено) Экспорт
	
	Если Метаданные.Обработки.Найти("РасширенныйВводКонтактнойИнформации") <> Неопределено Тогда
		Возврат Обработки["РасширенныйВводКонтактнойИнформации"].АдресXMLВXDTO(ЗначенияПолей, Представление, ОжидаемыйТип);
	КонецЕсли;
	
	// Пустой объект с представлением.
	ПространствоИмен = ПространствоИмен();
	Результат = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "КонтактнаяИнформация"));
	Результат.Состав = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "Адрес"));
	Результат.Состав.Состав = Представление;
	Результат.Представление = Представление;
	Возврат Результат;
	
КонецФункции

Функция НомерТелефонаВСтарыйСписокПолей(XDTOТелефон) Экспорт
	Результат = Новый СписокЗначений;
	
	Результат.Добавить(XDTOТелефон.КодСтраны,  "КодСтраны");
	Результат.Добавить(XDTOТелефон.КодГорода,  "КодГорода");
	Результат.Добавить(XDTOТелефон.Номер,      "НомерТелефона");
	Результат.Добавить(XDTOТелефон.Добавочный, "Добавочный");
	
	Возврат Результат;
КонецФункции

Функция КонтактнаяИнформацияВСтруктуруJSON(КонтактнаяИнформация, Тип, НастройкиКонвертации) Экспорт
	
	Результат = УправлениеКонтактнойИнформациейКлиентСервер.ОписаниеНовойКонтактнойИнформации(Тип);
	
	Если ТипЗнч(КонтактнаяИнформация) = Тип("Строка") Тогда
		
		Если УправлениеКонтактнойИнформациейКлиентСервер.ЭтоКонтактнаяИнформацияВXML(КонтактнаяИнформация) Тогда
			
			РезультатПреобразования = Новый Структура;
			
			XDTOКонтактнаяИнформация = КонтактнаяИнформацияИзXML(КонтактнаяИнформация, Тип, РезультатПреобразования, НастройкиКонвертации);
		Иначе
			Если СтрЧислоВхождений(КонтактнаяИнформация, ",") = 9 Тогда
				
				Результат.Value = КонтактнаяИнформация;
				Возврат Результат;
				
			Иначе
				XDTOКонтактнаяИнформация = КонтактнаяИнформацияИзXML(КонтактнаяИнформация, Тип,, НастройкиКонвертации);
			КонецЕсли;
		КонецЕсли;
	Иначе
		XDTOКонтактнаяИнформация = КонтактнаяИнформация;
		Тип = Перечисления.ТипыКонтактнойИнформации.Адрес;
	КонецЕсли;
	
	Результат.Value   = Строка(XDTOКонтактнаяИнформация.Представление);
	Результат.Comment = Строка(XDTOКонтактнаяИнформация.Комментарий);
	
	Если Тип <> Перечисления.ТипыКонтактнойИнформации.Адрес И Тип <> Перечисления.ТипыКонтактнойИнформации.Телефон Тогда
		Возврат Результат;
	КонецЕсли;
	
	ПространствоИмен = ПространствоИмен();
	Состав = XDTOКонтактнаяИнформация.Состав; // см. XDTOПакет.КонтактнаяИнформация.Адрес
	
	Если Состав = Неопределено Тогда
		Возврат Результат;
	КонецЕсли;
	
	XDTOТип = Состав.Тип();
	
	Если XDTOТип = ФабрикаXDTO.Тип(ПространствоИмен, "Адрес") Тогда
		
		Результат.Вставить("Country", Строка(Состав.Страна));
		Страна = Справочники.СтраныМира.НайтиПоНаименованию(Состав.Страна, Истина);
		Результат.Вставить("CountryCode", СокрЛП(Страна.Код));
		
	ИначеЕсли XDTOТип = ФабрикаXDTO.Тип(ПространствоИмен(), "НомерТелефона")
		Или XDTOТип = ФабрикаXDTO.Тип(ПространствоИмен(), "НомерФакса") Тогда
		
		Результат.CountryCode = Состав.КодСтраны;
		Результат.AreaCode    = Состав.КодГорода;
		Результат.Number      = Состав.Номер;
		Результат.ExtNumber   = Состав.Добавочный;
		
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции 

Функция КонтактнаяИнформацияXDTOПустая(Знач Результат)
	
	Состав = Результат.Свойства().Получить("Состав");
	Если Состав <> Неопределено Тогда
		Сведения = Результат.Состав.Свойства().Получить("Состав");
		Если Сведения <> Неопределено Тогда
			Если ТипЗнч(Результат.Состав.Состав) = Тип("Строка") Тогда
				Возврат ПустаяСтрока(Результат.Состав.Состав);
			ИначеЕсли ТипЗнч(Результат.Состав.Состав) = Тип("ОбъектXDTO") Тогда
				СписокСвойств = Результат.Состав.Состав.Свойства(); // КоллекцияСвойствXDTO
				Для каждого ПолеXDTO Из СписокСвойств Цикл
					Если ПолеXDTO.Имя = "ДопАдрЭл" Или ПолеXDTO.Имя = "СвРайМО" Тогда
						Продолжить;
					ИначеЕсли ЗначениеЗаполнено(Результат.Состав.Состав.Получить(ПолеXDTO.Имя)) Тогда
						Возврат Ложь;
					КонецЕсли;
				КонецЦикла;
			КонецЕсли;
		Иначе
			ПолеЗначение = Результат.Состав.Свойства().Получить("Значение");
			Если ПолеЗначение <> Неопределено Тогда
				Возврат ПустаяСтрока(Результат.Состав.Получить("Значение"));
			КонецЕсли;
		КонецЕсли;
		
	КонецЕсли;
	
	Возврат Истина;
	
КонецФункции

Функция ТипКонтактнойИнформацииИзОбъектаXDTO(КонтактнаяИнформация) Экспорт
	
	Если  ТипЗнч(КонтактнаяИнформация) = Тип("ОбъектXDTO") Тогда
		НайденТип = ?(КонтактнаяИнформация.Состав = Неопределено, Неопределено, КонтактнаяИнформация.Состав.Тип());
		Возврат СоответствиеXDTOТиповКонтактнойИнформации(НайденТип);
	КонецЕсли;
	
	Возврат Неопределено;
	
КонецФункции

Функция ТипКонтактнойИнформации(Знач XMLСтрока) Экспорт
	Возврат ЗначениеИзСтрокиXML(XSLT_ТипКонтактнойИнформацииПоСтрокеXML(XMLСтрока));
КонецФункции

Функция СоответствиеXDTOТиповКонтактнойИнформации(НайденТип) Экспорт
	
	ПространствоИмен = ПространствоИмен();
	
	СоответствиеТипов = Новый Соответствие;
	СоответствиеТипов.Вставить(ФабрикаXDTO.Тип(ПространствоИмен, "Адрес"), Перечисления.ТипыКонтактнойИнформации.Адрес);
	СоответствиеТипов.Вставить(ФабрикаXDTO.Тип(ПространствоИмен, "ЭлектроннаяПочта"), Перечисления.ТипыКонтактнойИнформации.АдресЭлектроннойПочты);
	СоответствиеТипов.Вставить(ФабрикаXDTO.Тип(ПространствоИмен, "ВебСайт"), Перечисления.ТипыКонтактнойИнформации.ВебСтраница);
	СоответствиеТипов.Вставить(ФабрикаXDTO.Тип(ПространствоИмен, "НомерТелефона"), Перечисления.ТипыКонтактнойИнформации.Телефон);
	СоответствиеТипов.Вставить(ФабрикаXDTO.Тип(ПространствоИмен, "НомерФакса"), Перечисления.ТипыКонтактнойИнформации.Факс);
	СоответствиеТипов.Вставить(ФабрикаXDTO.Тип(ПространствоИмен, "Skype"), Перечисления.ТипыКонтактнойИнформации.Skype);
	СоответствиеТипов.Вставить(ФабрикаXDTO.Тип(ПространствоИмен, "Прочее"), Перечисления.ТипыКонтактнойИнформации.Другое);
	
	Возврат СоответствиеТипов[НайденТип];

КонецФункции

Функция ПространствоИмен() Экспорт
	Возврат "http://www.v8.1c.ru/ssl/contactinfo"; // @Non-NLS
КонецФункции

#Область СлужебныеПроцедурыИФункцииПоРаботеСXML

Функция СтрокаСоставаКонтактнойИнформации(Знач Текст, Знач НовоеЗначение = Неопределено) Экспорт
	Чтение = Новый ЧтениеXML;
	Чтение.УстановитьСтроку(Текст);
	ОбъектXDTO = ФабрикаXDTO.ПрочитатьXML(Чтение, 
	ФабрикаXDTO.Тип(ПространствоИмен(), "КонтактнаяИнформация"));
	
	Состав = ОбъектXDTO.Состав;
	Если Состав <> Неопределено 
		И Состав.Свойства().Получить("Значение") <> Неопределено
		И ТипЗнч(Состав.Значение) = Тип("Строка") Тогда
		Возврат Состав.Значение;
	КонецЕсли;
	
	Возврат Неопределено;
КонецФункции

// Сравнивает два экземпляра контактной информации.
//
// Параметры:
//    Данные1 - ОбъектXDTO - объект с контактной информацией.
//            - Строка     - контактная информация в формате XML.
//            - Структура  - описание контактной информацию. Ожидаются поля:
//                 * ЗначенияПолей - Строка
//                                 - Структура
//                                 - СписокЗначений
//                                 - Соответствие - поля контактной информации.
//                 * Представление - Строка - представление. Используется в случае, если не удалось вычислить
//                                            представление из ЗначенияПолей (отсутствие в них поля Представление).
//                 * Комментарий - Строка - комментарий. Используется в том случае, если не удалось вычислить комментарий
//                                          из ЗначенияПолей.
//                 * ВидКонтактнойИнформации - СправочникСсылка.ВидыКонтактнойИнформации
//                                           - ПеречислениеСсылка.ТипыКонтактнойИнформации
//                                           - Структура -
//                                             используется в том случае, если не удалось вычислить тип из ЗначенияПолей.
//    Данные2 - ОбъектXDTO
//            - Строка
//            - Структура - смотри описание параметра Данные1.
//    Результат - ТаблицаЗначений:
//      * Путь      - Строка - XPath, идентифицирующий отличающееся значение. Значение "ТипКонтактнойИнформации"
//                             означает, что переданные экземпляры контактной информации различаются типом.
//      * Описание  - Строка - описание отличающегося реквизита в терминах предметной области.
//      * Значение1 - Строка - значение, соответствующая объекту, переданному в параметре Данные1.
//      * Значение2 - Строка - значение, соответствующая объекту, переданному в параметре Данные2.
//
//
// Возвращаемое значение:
//     ТаблицаЗначений: - таблица отличающихся полей со следующими колонками:
//        * Путь      - Строка - XPath, идентифицирующий отличающееся значение. Значение "ТипКонтактнойИнформации"
//                               означает, что переданные экземпляры контактной информации различаются типом.
//        * Описание  - Строка - описание отличающегося реквизита в терминах предметной области.
//        * Значение1 - Строка - значение, соответствующая объекту, переданному в параметре Данные1.
//        * Значение2 - Строка - значение, соответствующая объекту, переданному в параметре Данные2.
//
Функция РазличияКонтактнойИнформации(Знач Данные1, Знач Данные2, Результат) Экспорт
	
	ДанныеКИ1 = ПривестиКонтактнуюИнформациюXML(Данные1);
	ДанныеКИ2 = ПривестиКонтактнуюИнформациюXML(Данные2);
	
	ТипКонтактнойИнформации = ДанныеКИ1.ТипКонтактнойИнформации;
	Если ТипКонтактнойИнформации <> ДанныеКИ2.ТипКонтактнойИнформации Тогда
		// Различные типы, дальше не сравниваем.
		СтрокаРезультата = Результат.Добавить();
		СтрокаРезультата.Путь = "ТипКонтактнойИнформации";
		СтрокаРезультата.Значение1 = ДанныеКИ1.ТипКонтактнойИнформации;
		СтрокаРезультата.Значение2 = ДанныеКИ2.ТипКонтактнойИнформации;
		СтрокаРезультата.Описание  = НСтр("ru = 'Различные типы контактной информации'");
		Возврат Результат;
	КонецЕсли;
	
	ТекстРазличияXML = XSLT_ТаблицаЗначенийРазличияXML(ДанныеКИ1.ДанныеXML, ДанныеКИ2.ДанныеXML);
	
	// Отдаем интерпретацию в зависимости от типа.
	Возврат ЗначениеИзСтрокиXML( XSLT_ИнтерпретацияРазличияXMLКонтактнойИнформации(
			ТекстРазличияXML, ТипКонтактнойИнформации));
	
КонецФункции

// Параметры:
//  Данные - см. УправлениеКонтактнойИнформациейКлиентСервер.ОписаниеКонтактнойИнформации
// 
// Возвращаемое значение:
//  Структура:
//    * ДанныеXML - Строка 
//    * ТипКонтактнойИнформации - ПеречислениеСсылка.ТипыКонтактнойИнформации
//
Функция ПривестиКонтактнуюИнформациюXML(Знач Данные) Экспорт
	
	XMLСтрока               = "";
	ЗначенияПолей           = "";
	Комментарий             = Неопределено;
	ТипКонтактнойИнформации = Неопределено;
	
	Результат = УправлениеКонтактнойИнформацией.ПоляКонтактнойИнформацииДляПреобразования();
	
	Если ТипЗнч(Данные) = Тип("ОбъектXDTO") Тогда
		XMLСтрока = КонтактнаяИнформацияXDTOВXML(Данные);
		ТипКонтактнойИнформации = ЗначениеИзСтрокиXML(XSLT_ТипКонтактнойИнформацииПоСтрокеXML(XMLСтрока));
	Иначе
		
		Если ТипЗнч(Данные) = Тип("Структура") Тогда
			ЗначенияПолей = ?(Данные.Свойство("ЗначенияПолей"), Данные.ЗначенияПолей, "");
			Комментарий = ?(Данные.Свойство("Комментарий"), Данные.Комментарий, "");
			
			Если Данные.Свойство("ВидКонтактнойИнформации") И Данные.ВидКонтактнойИнформации <> Неопределено Тогда
				ТипКонтактнойИнформации = УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ТипВидаКонтактнойИнформации(Данные.ВидКонтактнойИнформации);
			КонецЕсли;
			
		ИначеЕсли ТипЗнч(Данные) = Тип("Строка") Тогда
			ЗначенияПолей = Данные;
		КонецЕсли;
		
		Если УправлениеКонтактнойИнформациейКлиентСервер.ЭтоКонтактнаяИнформацияВJSON(ЗначенияПолей) Тогда
			XMLСтрока = КонтактнаяИнформацияИзJSONВXML(ЗначенияПолей, ТипКонтактнойИнформации);
			ТипКонтактнойИнформации = ЗначениеИзСтрокиXML(XSLT_ТипКонтактнойИнформацииПоСтрокеXML(XMLСтрока));
		ИначеЕсли УправлениеКонтактнойИнформациейКлиентСервер.ЭтоКонтактнаяИнформацияВXML(ЗначенияПолей) Тогда
			XMLСтрока = ЗначенияПолей;
			ТипКонтактнойИнформации = ЗначениеИзСтрокиXML(XSLT_ТипКонтактнойИнформацииПоСтрокеXML(XMLСтрока));
		ИначеЕсли ТипЗнч(ЗначенияПолей) = Тип("Строка") И ТипКонтактнойИнформации = Неопределено Тогда
			
			// старый формат ключ-значение
			Если СтрНайти(ВРег(ЗначенияПолей), "РЕГИОН=") > 0 Тогда
				ТипКонтактнойИнформации = Перечисления.ТипыКонтактнойИнформации.Адрес;
			ИначеЕсли СтрНайти(ВРег(ЗначенияПолей), "НОМЕРТЕЛЕФОНА=") > 0 Тогда
				ТипКонтактнойИнформации = Перечисления.ТипыКонтактнойИнформации.Телефон;
			ИначеЕсли СтрНайти(ВРег(ЗначенияПолей), "НОМЕРФАКСА=") > 0 Тогда
				ТипКонтактнойИнформации = Перечисления.ТипыКонтактнойИнформации.Факс;
			Иначе
				ТипКонтактнойИнформации = Перечисления.ТипыКонтактнойИнформации.Другое;
			КонецЕсли;
			
		КонецЕсли;
	
	КонецЕсли;
	
	Результат.ТипКонтактнойИнформации = ТипКонтактнойИнформации;
	
	Если ЗначениеЗаполнено(XMLСтрока) Тогда
		
		Если Не ПустаяСтрока(Комментарий) Тогда
			УправлениеКонтактнойИнформацией.УстановитьКомментарийКонтактнойИнформации(ЗначенияПолей, Комментарий);
		КонецЕсли;
		
		Результат.ДанныеXML = XMLСтрока;
		Возврат Результат;
		
	КонецЕсли;
	
	// Разбираем по ЗначенияПолей, ВидКонтактнойИнформации, Представление.
	ТипЗначенийПолей = ТипЗнч(ЗначенияПолей);
	Если ТипЗначенийПолей = Тип("Строка") Тогда
		// Текст из пар ключ-значение
		СтрокаXMLСтруктуры = XSLT_СтрокаКлючЗначениеВСтруктуру(ЗначенияПолей)
		
	ИначеЕсли ТипЗначенийПолей = Тип("СписокЗначений") Тогда
		// Список значений
		СтрокаXMLСтруктуры = XSLT_СписокЗначенийВСтруктуру( ЗначениеВСтрокуXML(ЗначенияПолей) );
		
	ИначеЕсли ТипЗначенийПолей = Тип("Соответствие") Тогда
		// Соответствие
		СтрокаXMLСтруктуры = XSLT_СоответствиеВСтруктуру( ЗначениеВСтрокуXML(ЗначенияПолей) );
		
	ИначеЕсли ТипЗначенийПолей = Тип("ОбъектXDTO") Тогда
		// Ожидаем структуру
		Если ЗначенияПолей.Состав.Страна = Неопределено Тогда
			ЗначенияПолей.Состав.Страна = "";
		КонецЕсли;
		Если ЗначенияПолей.Состав.Состав = Неопределено Тогда
			ЗначенияПолей.Состав.Состав = "";
		КонецЕсли;
		
		СтрокаXMLСтруктуры = ЗначениеВСтрокуXML(ЗначенияПолей);
	Иначе
		// Ожидаем структуру
		СтрокаXMLСтруктуры = ЗначениеВСтрокуXML(ЗначенияПолей);
		
	КонецЕсли;
	
	ВсеТипы = Перечисления.ТипыКонтактнойИнформации;
	Если ТипКонтактнойИнформации = ВсеТипы.Адрес Тогда
		Результат.ДанныеXML = XSLT_СтруктураВАдрес(СтрокаXMLСтруктуры, Данные.Представление, Комментарий);
		
	ИначеЕсли ТипКонтактнойИнформации = ВсеТипы.АдресЭлектроннойПочты Тогда
		Результат.ДанныеXML = XSLT_СтруктураВАдресЭлектроннойПочты(СтрокаXMLСтруктуры, Данные.Представление, Комментарий);
		
	ИначеЕсли ТипКонтактнойИнформации = ВсеТипы.ВебСтраница Тогда
		Результат.ДанныеXML = XSLT_СтруктураВВебСтраницу(СтрокаXMLСтруктуры, Данные.Представление, Комментарий);
		
	ИначеЕсли ТипКонтактнойИнформации = ВсеТипы.Телефон Тогда
		Результат.ДанныеXML = XSLT_СтруктураВТелефон(СтрокаXMLСтруктуры, Данные.Представление, Комментарий);
		
	ИначеЕсли ТипКонтактнойИнформации = ВсеТипы.Факс Тогда
		Результат.ДанныеXML = XSLT_СтруктураВФакс(СтрокаXMLСтруктуры, Данные.Представление, Комментарий);
		
	ИначеЕсли ТипКонтактнойИнформации = ВсеТипы.Другое 
		Или ТипКонтактнойИнформации = ВсеТипы.Skype Тогда
		Результат.ДанныеXML = XSLT_СтруктураВДругое(СтрокаXMLСтруктуры, Данные.Представление, Комментарий);
		
	Иначе
		ВызватьИсключение НСтр("ru = 'Ошибка параметров преобразования, не определен тип контактной информации'");
		
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Функция КонтактнаяИнформацияXDTOВXML(ОбъектXDTOИнформации) Экспорт
	
	Запись = Новый ЗаписьXML;
	Запись.УстановитьСтроку(Новый ПараметрыЗаписиXML(, , Ложь, Ложь, ""));
	
	Если ОбъектXDTOИнформации <> Неопределено Тогда
		ФабрикаXDTO.ЗаписатьXML(Запись, ОбъектXDTOИнформации);
	КонецЕсли;
	
	Результат = СтрЗаменить(Запись.Закрыть(), Символы.ПС, "&#10;");
	Результат = СтрЗаменить(Результат, "<ВнутригРайон/>", "");// Совместимость с КЛАДР
	
	Если УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ДоступныМодулиРаботаСАдресами() Тогда
		МодульРаботаСАдресами = ОбщегоНазначения.ОбщийМодуль("РаботаСАдресами");
		Результат = МодульРаботаСАдресами.ПередЗаписьюXDTOКонтактнаяИнформация(Результат);
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Параметры:
//  ЗначенияПолей - Строка
//  ТипКонтактнойИнформации - ПеречислениеСсылка.ТипыКонтактнойИнформации
//  Параметры - Структура
//  ОсновнаяСтрана - СправочникСсылка.СтраныМира
// 
// Возвращаемое значение:
//  ОбъектXDTO, ЗначениеXDTO, Неопределено
//
Функция ИзвлечьСтарыйФорматАдреса(Знач ЗначенияПолей, Знач ТипКонтактнойИнформации, Параметры, ОсновнаяСтрана) Экспорт
	
	Если УправлениеКонтактнойИнформациейКлиентСервер.ЭтоКонтактнаяИнформацияВXML(ЗначенияПолей)
		И ТипКонтактнойИнформации = Перечисления.ТипыКонтактнойИнформации.Адрес Тогда
		РезультатыЧтения = Новый Структура;
		XDTOКонтактная = КонтактнаяИнформацияИзXML(ЗначенияПолей, ТипКонтактнойИнформации, РезультатыЧтения);
		Если РезультатыЧтения.Свойство("ТекстОшибки") Тогда
			// Распознали с ошибками, сообщим при открытии.
			XDTOКонтактная.Представление   = Параметры.Представление;
			XDTOКонтактная.Состав.Страна   = Строка(ОсновнаяСтрана);
		КонецЕсли;
	Иначе
		XDTOКонтактная = АдресXMLВXDTO(ЗначенияПолей, Параметры.Представление, );
		Если Параметры.Свойство("Страна") И ЗначениеЗаполнено(Параметры.Страна) Тогда
			Если ТипЗнч(Параметры.Страна) = ТипЗнч(Справочники.СтраныМира.ПустаяСсылка()) Тогда
				XDTOКонтактная.Состав.Страна = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Параметры.Страна, "Наименование");
			Иначе
				XDTOКонтактная.Состав.Страна = Строка(Параметры.Страна);
			КонецЕсли;
		Иначе
			XDTOКонтактная.Состав.Страна = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(ОсновнаяСтрана, "Наименование");
		КонецЕсли;
	КонецЕсли;
	Если Параметры.Комментарий <> Неопределено Тогда
		// Ставим новый комментарий, иначе он придет из информации.
		XDTOКонтактная.Комментарий = Параметры.Комментарий;
	КонецЕсли;
	
	Возврат XDTOКонтактная;

КонецФункции

#КонецОбласти

#Область СлужебныеПроцедурыИФункцииПоРаботеСXSLT

Функция XSLT_ТаблицаЗначенийРазличияXML(Текст1, Текст2)
	
	Преобразователь = ПреобразованиеXSLT_ТаблицаЗначенийРазличияXML();
	
	Построитель = Новый ТекстовыйДокумент;
	Построитель.ДобавитьСтроку("<dn><f>");
	Построитель.ДобавитьСтроку( XSLT_УдалитьОписаниеXML(Текст1) );
	Построитель.ДобавитьСтроку("</f><s>");
	Построитель.ДобавитьСтроку( XSLT_УдалитьОписаниеXML(Текст2) );
	Построитель.ДобавитьСтроку("</s></dn>");
	
	Возврат Преобразователь.ПреобразоватьИзСтроки(Построитель.ПолучитьТекст());
	
КонецФункции

Функция XSLT_СтрокаКлючЗначениеВСтруктуру(Знач Текст) 
	
	Преобразователь = ПреобразованиеXSLT_СтрокаКлючЗначениеВСтруктуру();
	Возврат Преобразователь.ПреобразоватьИзСтроки(XSLT_УзелСтрокиПараметра(Текст));
	
КонецФункции

Функция XSLT_СписокЗначенийВСтруктуру(Текст)
	
	Преобразователь = ПреобразованиеXSLT_СписокЗначенийВСтруктуру();
	Возврат Преобразователь.ПреобразоватьИзСтроки(Текст);
	
КонецФункции

Функция XSLT_СоответствиеВСтруктуру(Текст)
	
	Преобразователь = ПреобразованиеXSLT_СоответствиеВСтруктуру();
	Возврат Преобразователь.ПреобразоватьИзСтроки(Текст);
	
КонецФункции

Функция XSLT_ИнтерпретацияРазличияXMLКонтактнойИнформации(Знач Текст, Знач ТипКонтактнойИнформации) 
	
	Преобразователь = ПреобразованиеXSLT_ИнтерпретацияРазличияXMLКонтактнойИнформации(
		ТипКонтактнойИнформации);
	Возврат Преобразователь.ПреобразоватьИзСтроки(Текст);
	
КонецФункции

Функция XSLT_СтруктураВАдрес(Знач Текст, Знач Представление = Неопределено, Знач Комментарий = Неопределено)
	
	Преобразователь = ПреобразованиеXSLT_ПреобразованиеXSL();
	Возврат XSLT_КонтрольПредставленияИКомментария(
		Преобразователь.ПреобразоватьИзСтроки(Текст),
		Представление, Комментарий);
		
КонецФункции

Функция XSLT_СтруктураВАдресЭлектроннойПочты(Знач Текст, Знач Представление = Неопределено, Знач Комментарий = Неопределено)
	
	Преобразователь = ПреобразованиеXSLT_СтруктураВАдресЭлектроннойПочты();
	Возврат XSLT_КонтрольПредставленияИКомментария(
		XSLT_КонтрольСтроковогоЗначенияПростогоТипа(Преобразователь.ПреобразоватьИзСтроки(Текст), Представление), 
		Представление, Комментарий);
		
КонецФункции

Функция XSLT_СтруктураВВебСтраницу(Знач Текст, Знач Представление = Неопределено, Знач Комментарий = Неопределено)
	Преобразователь = ПреобразованиеXSLT_СтруктураВВебСтраницу();
	
	Возврат XSLT_КонтрольПредставленияИКомментария(
		XSLT_КонтрольСтроковогоЗначенияПростогоТипа( Преобразователь.ПреобразоватьИзСтроки(Текст), Представление),
		Представление, Комментарий);
		
КонецФункции

Функция XSLT_СтруктураВТелефон(Знач Текст, Знач Представление = Неопределено, Знач Комментарий = Неопределено)
	Преобразователь = ПреобразованиеXSLT_СтруктураВТелефон();
	Возврат XSLT_КонтрольПредставленияИКомментария(
		Преобразователь.ПреобразоватьИзСтроки(Текст),
		Представление, Комментарий);
КонецФункции

Функция XSLT_СтруктураВФакс(Знач Текст, Знач Представление = Неопределено, Знач Комментарий = Неопределено)
	
	Преобразователь = ПреобразованиеXSLT_СтруктураВФакс();
	Возврат XSLT_КонтрольПредставленияИКомментария(
		Преобразователь.ПреобразоватьИзСтроки(Текст),
		Представление, Комментарий);
		
КонецФункции

Функция XSLT_СтруктураВДругое(Знач Текст, Знач Представление = Неопределено, Знач Комментарий = Неопределено)
	
	Преобразователь = ПреобразованиеXSLT_СтруктураВДругое();
	Возврат XSLT_КонтрольПредставленияИКомментария(
		XSLT_КонтрольСтроковогоЗначенияПростогоТипа( Преобразователь.ПреобразоватьИзСтроки(Текст), Представление),
		Представление, Комментарий);
		
КонецФункции

Функция XSLT_КонтрольПредставленияИКомментария(Знач Текст, Знач Представление = Неопределено, Знач Комментарий = Неопределено)
	
	Если Представление = Неопределено И Комментарий = Неопределено Тогда
		Возврат Текст;
	КонецЕсли;
	
	XSLT_Текст = Новый ТекстовыйДокумент;
	XSLT_Текст.ДобавитьСтроку("
		|<xsl:stylesheet version=""1.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform""
		|  xmlns:tns=""http://www.v8.1c.ru/ssl/contactinfo""
		|  xmlns=""http://www.v8.1c.ru/ssl/contactinfo"" 
		|>
		|  <xsl:output method=""xml"" omit-xml-declaration=""yes"" indent=""yes"" encoding=""utf-8""/>
		|
		|  <xsl:template match=""node() | @*"">
		|    <xsl:copy>
		|      <xsl:apply-templates select=""node() | @*"" />
		|    </xsl:copy>
		|  </xsl:template>
		|");
		
	Если Представление <> Неопределено Тогда
		XSLT_Текст.ДобавитьСтроку("
		|  <xsl:template match=""tns:КонтактнаяИнформация/@Представление"">
		|    <xsl:attribute name=""Представление"">
		|      <xsl:choose>
		|        <xsl:when test="".=''"">" + НормализованнаяСтрокаXML(Представление) + "</xsl:when>
		|        <xsl:otherwise>
		|          <xsl:value-of select="".""/>
		|        </xsl:otherwise>
		|      </xsl:choose>
		|    </xsl:attribute>
		|  </xsl:template>
		|");
	КонецЕсли;
	
	Если Комментарий <> Неопределено Тогда
		XSLT_Текст.ДобавитьСтроку("
		|  <xsl:template match=""tns:КонтактнаяИнформация/tns:Комментарий"">
		|    <xsl:element name=""Комментарий"">
		|      <xsl:choose>
		|        <xsl:when test="".=''"">" + НормализованнаяСтрокаXML(Комментарий) + "</xsl:when>
		|        <xsl:otherwise>
		|          <xsl:value-of select="".""/>
		|        </xsl:otherwise>
		|      </xsl:choose>
		|    </xsl:element>
		|  </xsl:template>
		|");
	КонецЕсли;
		XSLT_Текст.ДобавитьСтроку("
		|</xsl:stylesheet>
		|");
		
	Преобразователь = Новый ПреобразованиеXSL;
	Преобразователь.ЗагрузитьТаблицуСтилейXSLИзСтроки(XSLT_Текст.ПолучитьТекст());
	
	Возврат Преобразователь.ПреобразоватьИзСтроки(Текст);
КонецФункции

Функция XSLT_КонтрольСтроковогоЗначенияПростогоТипа(Знач Текст, Знач Представление)
	
	Если Представление = Неопределено Тогда
		Возврат Текст;
	КонецЕсли;
	
	Преобразователь = Новый ПреобразованиеXSL;
	Преобразователь.ЗагрузитьТаблицуСтилейXSLИзСтроки("
		|<xsl:stylesheet version=""1.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform""
		|  xmlns:tns=""http://www.v8.1c.ru/ssl/contactinfo""
		|>
		|  <xsl:output method=""xml"" omit-xml-declaration=""yes"" indent=""yes"" encoding=""utf-8""/>
		|  
		|  <xsl:template match=""node() | @*"">
		|    <xsl:copy>
		|      <xsl:apply-templates select=""node() | @*"" />
		|    </xsl:copy>
		|  </xsl:template>
		|  
		|  <xsl:template match=""tns:КонтактнаяИнформация/tns:Состав/@Значение"">
		|    <xsl:attribute name=""Значение"">
		|      <xsl:choose>
		|        <xsl:when test="".=''"">" + НормализованнаяСтрокаXML(Представление) + "</xsl:when>
		|        <xsl:otherwise>
		|          <xsl:value-of select="".""/>
		|        </xsl:otherwise>
		|      </xsl:choose>
		|    </xsl:attribute>
		|  </xsl:template>
		|
		|</xsl:stylesheet>
		|");
	
	Возврат Преобразователь.ПреобразоватьИзСтроки(Текст);
КонецФункции

Функция XSLT_УзелСтрокиПараметра(Знач Текст, Знач ИмяЭлемента = "ExternalParamNode")
	
	// Через запись xml для маскировки спецсимволов.
	Запись = Новый ЗаписьXML;
	Запись.УстановитьСтроку();
	Запись.ЗаписатьНачалоЭлемента(ИмяЭлемента);
	Запись.ЗаписатьТекст(Текст);
	Запись.ЗаписатьКонецЭлемента();
	Возврат Запись.Закрыть();
	
КонецФункции

Функция XSLT_УдалитьОписаниеXML(Знач Текст)
	
	Преобразователь = ПреобразованиеXSLT_УдалитьОписаниеXML();
	Возврат Преобразователь.ПреобразоватьИзСтроки(СокрЛ(Текст));
	
КонецФункции

Функция XSLT_ТипКонтактнойИнформацииПоСтрокеXML(Знач Текст)
	
	Преобразователь = ПреобразованиеXSLT_ТипКонтактнойИнформацииПоСтрокеXML();
	Возврат Преобразователь.ПреобразоватьИзСтроки(СокрЛ(Текст));
	
КонецФункции

Функция ЗначениеИзСтрокиXML(Знач Текст)
	
	ЧтениеXML = Новый ЧтениеXML;
	ЧтениеXML.УстановитьСтроку(Текст);
	Возврат СериализаторXDTO.ПрочитатьXML(ЧтениеXML);
	
КонецФункции

Функция ЗначениеВСтрокуXML(Знач Значение)
	
	ЗаписьXML = Новый ЗаписьXML;
	ЗаписьXML.УстановитьСтроку(Новый ПараметрыЗаписиXML(, , Ложь, Ложь, ""));
	СериализаторXDTO.ЗаписатьXML(ЗаписьXML, Значение, НазначениеТипаXML.Явное);
	// Платформенный сериализатор позволяет записать в значение атрибутов перенос строки.
	Возврат СтрЗаменить(ЗаписьXML.Закрыть(), Символы.ПС, "&#10;");
	
КонецФункции

Функция МногострочнаяСтрокаXML(Знач Текст)
	
	Возврат СтрЗаменить(Текст, Символы.ПС, "&#10;");
	
КонецФункции

Функция НормализованнаяСтрокаXML(Знач Текст)
	
	Результат = СтрЗаменить(Текст,     "&",  "&amp;");
	Результат = СтрЗаменить(Результат, "'",  "&apos;");
	Результат = СтрЗаменить(Результат, "<",  "&lt;");
	Результат = СтрЗаменить(Результат, ">",  "&gt;");
	Результат = СтрЗаменить(Результат, """", "&quot;");
	Возврат МногострочнаяСтрокаXML(Результат);
	
КонецФункции

Функция ПреобразованиеXSLT_ТаблицаЗначенийРазличияXML()
	Преобразователь = Новый ПреобразованиеXSL;
	
	// Пространство имен должно быть пустым!
	Преобразователь.ЗагрузитьТаблицуСтилейXSLИзСтроки("
		|<xsl:stylesheet version=""1.0""
		|  xmlns:xsl=""http://www.w3.org/1999/XSL/Transform""
		|  xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""
		|  xmlns:xs=""http://www.w3.org/2001/XMLSchema""
		|
		|  xmlns:str=""http://exslt.org/strings""
		|  xmlns:exsl=""http://exslt.org/common""
		|
		|  extension-element-prefixes=""str exsl""
		|>
		|<xsl:output method=""xml"" omit-xml-declaration=""yes"" indent=""yes"" encoding=""utf-8""/>
		|" + XSLT_ШаблоныСтроковыхФункций() + "
		|" + XSLT_ШаблоныФункцийXPath() + "
		|
		|  <!-- parce tree elements to xpath-value -->
		|  <xsl:template match=""node()"" mode=""action"">
		|    
		|    <xsl:variable name=""text"">
		|      <xsl:call-template name=""str-trim-all"">
		|        <xsl:with-param name=""str"" select=""text()"" />
		|      </xsl:call-template>
		|    </xsl:variable>
		|
		|    <xsl:if test=""$text!=''"">
		|      <xsl:element name=""item"">
		|        <xsl:attribute name=""path"">
		|          <xsl:variable name=""tmp-path"">
		|            <xsl:call-template name=""build-path"" />
		|          </xsl:variable>
		|          <xsl:value-of select=""substring($tmp-path, 6)"" /> <!-- pass '/dn/f' or '/dn/s' -->
		|        </xsl:attribute>
		|        <xsl:attribute name=""value"">
		|          <xsl:value-of select=""text()"" />
		|        </xsl:attribute>
		|      </xsl:element>
		|    </xsl:if>
		|
		|    <xsl:apply-templates select=""@* | node()"" mode=""action""/>
		|  </xsl:template>
		|
		|  <!-- parce tree attributes to xpath-value -->
		|  <xsl:template match=""@*"" mode=""action"">
		|    <xsl:element name=""item"">
		|      <xsl:attribute name=""path"">
		|          <xsl:variable name=""tmp-path"">
		|            <xsl:call-template name=""build-path"" />
		|          </xsl:variable>
		|          <xsl:value-of select=""substring($tmp-path, 6)"" /> <!-- pass '/dn/f' or '/dn/s' -->
		|      </xsl:attribute>
		|      <xsl:attribute name=""value"">
		|        <xsl:value-of select=""."" />
		|      </xsl:attribute>
		|    </xsl:element>
		|  </xsl:template>
		|
		|  <!-- main -->
		|  <xsl:variable name=""dummy"">
		|    <xsl:element name=""first"">
		|      <xsl:apply-templates select=""/dn/f"" mode=""action"" />
		|    </xsl:element> 
		|    <xsl:element name=""second"">
		|      <xsl:apply-templates select=""/dn/s"" mode=""action"" />
		|    </xsl:element>
		|  </xsl:variable>
		|  <xsl:variable name=""dummy-nodeset"" select=""exsl:node-set($dummy)"" />
		|  <xsl:variable name=""first-items"" select=""$dummy-nodeset/first/item"" />
		|  <xsl:variable name=""second-items"" select=""$dummy-nodeset/second/item"" />
		|
		|  <xsl:template match=""/"">
		|    
		|    <!-- first vs second -->
		|    <xsl:variable name=""first-second"">
		|      <xsl:for-each select=""$first-items"">
		|        <xsl:call-template name=""compare"">
		|          <xsl:with-param name=""check"" select=""$second-items"" />
		|        </xsl:call-template>
		|      </xsl:for-each>
		|    </xsl:variable>
		|    <xsl:variable name=""first-second-nodeset"" select=""exsl:node-set($first-second)"" />
		|
		|    <!-- second vs first without doubles -->
		|    <xsl:variable name=""doubles"" select=""$first-second-nodeset/item"" />
		|    <xsl:variable name=""second-first"">
		|      <xsl:for-each select=""$second-items"">
		|        <xsl:call-template name=""compare"">
		|          <xsl:with-param name=""check"" select=""$first-items"" />
		|          <xsl:with-param name=""doubles"" select=""$doubles"" />
		|        </xsl:call-template>
		|      </xsl:for-each>
		|    </xsl:variable>
		|      
		|    <!-- result -->
		|    <ValueTable xmlns=""http://v8.1c.ru/8.1/data/core"" xmlns:xs=""http://www.w3.org/2001/XMLSchema"" xsi:type=""ValueTable"">
		|      <column>
		|        <Name xsi:type=""xs:string"">Путь</Name>
		|        <ValueType>
		|           <Type>xs:string</Type>
		|           <StringQualifiers><Length>0</Length><AllowedLength>Variable</AllowedLength></StringQualifiers>
		|        </ValueType>
		|      </column>
		|      <column>
		|        <Name xsi:type=""xs:string"">Значение1</Name>
		|        <ValueType>
		|           <Type>xs:string</Type>
		|           <StringQualifiers><Length>0</Length><AllowedLength>Variable</AllowedLength></StringQualifiers>
		|        </ValueType>
		|      </column>
		|      <column>
		|        <Name xsi:type=""xs:string"">Значение2</Name>
		|        <ValueType>
		|           <Type>xs:string</Type>
		|           <StringQualifiers><Length>0</Length><AllowedLength>Variable</AllowedLength></StringQualifiers>
		|        </ValueType>
		|      </column>
		|
		|      <xsl:for-each select=""$first-second-nodeset/item | exsl:node-set($second-first)/item"">
		|        <xsl:element name=""row"">
		|           <xsl:element name=""Value"">
		|             <xsl:value-of select=""@path""/>
		|           </xsl:element>
		|           <xsl:element name=""Value"">
		|             <xsl:value-of select=""@value1""/>
		|           </xsl:element>
		|           <xsl:element name=""Value"">
		|             <xsl:value-of select=""@value2""/>
		|           </xsl:element>
		|        </xsl:element>
		|      </xsl:for-each>
		|
		|    </ValueTable>
		|
		|  </xsl:template>
		|  <!-- /main -->
		|
		|  <!-- compare sub -->
		|  <xsl:template name=""compare"">
		|    <xsl:param name=""check"" />
		|    <xsl:param name=""doubles"" select=""/.."" />
		|    
		|    <xsl:variable name=""path""  select=""@path""/>
		|    <xsl:variable name=""value"" select=""@value""/>
		|    <xsl:variable name=""diff""  select=""$check[@path=$path]""/>
		|    <xsl:choose>
		|      <xsl:when test=""count($diff)=0"">
		|        <xsl:if test=""count($doubles[@path=$path and @value1='' and @value2=$value])=0"">
		|          <xsl:element name=""item"">
		|            <xsl:attribute name=""path"">   <xsl:value-of select=""$path""/> </xsl:attribute>
		|            <xsl:attribute name=""value1""> <xsl:value-of select=""$value""/> </xsl:attribute>
		|            <xsl:attribute name=""value2"" />
		|          </xsl:element>
		|        </xsl:if>
		|      </xsl:when>
		|      <xsl:otherwise>
		|
		|        <xsl:for-each select=""$diff[@value!=$value]"">
		|            <xsl:variable name=""diff-value"" select=""@value""/>
		|            <xsl:if test=""count($doubles[@path=$path and @value1=$diff-value and @value2=$value])=0"">
		|              <xsl:element name=""item"">
		|                <xsl:attribute name=""path"">   <xsl:value-of select=""$path""/>  </xsl:attribute>
		|                <xsl:attribute name=""value1""> <xsl:value-of select=""$value""/> </xsl:attribute>
		|                <xsl:attribute name=""value2""> <xsl:value-of select=""@value""/> </xsl:attribute>
		|              </xsl:element>
		|            </xsl:if>
		|        </xsl:for-each>
		|      </xsl:otherwise>
		|    </xsl:choose>
		|  </xsl:template>
		|  
		|</xsl:stylesheet>
		|");
		
	Возврат Преобразователь;
КонецФункции

Функция ПреобразованиеXSLT_СтрокаКлючЗначениеВСтруктуру()
	Преобразователь = Новый ПреобразованиеXSL;
	Преобразователь.ЗагрузитьТаблицуСтилейXSLИзСтроки("
		|<xsl:stylesheet version=""1.0""
		|  xmlns:xsl=""http://www.w3.org/1999/XSL/Transform""
		|  xmlns:str=""http://exslt.org/strings""
		|  extension-element-prefixes=""str""
		|>
		|<xsl:output method=""xml"" omit-xml-declaration=""yes"" indent=""yes"" encoding=""utf-8""/>
		|" + XSLT_ШаблоныСтроковыхФункций() + "
		|
		|  <xsl:template match=""ExternalParamNode"">
		|
		|    <xsl:variable name=""source"">
		|      <xsl:call-template name=""str-replace-all"">
		|        <xsl:with-param name=""str"" select=""."" />
		|        <xsl:with-param name=""search-for"" select=""'&#10;&#09;'"" />
		|        <xsl:with-param name=""replace-by"" select=""'&#13;'"" />
		|      </xsl:call-template>
		|    </xsl:variable>
		|
		|    <Structure xmlns=""http://v8.1c.ru/8.1/data/core"" xmlns:xs=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xsi:type=""Structure"">
		|
		|     <xsl:for-each select=""str:tokenize($source, '&#10;')"" >
		|       <xsl:if test=""contains(., '=')"">
		|
		|         <xsl:element name=""Property"">
		|           <xsl:attribute name=""name"" >
		|             <xsl:call-template name=""str-trim-all"">
		|               <xsl:with-param name=""str"" select=""substring-before(., '=')"" />
		|             </xsl:call-template>
		|           </xsl:attribute>
		|
		|           <Value xsi:type=""xs:string"">
		|             <xsl:call-template name=""str-replace-all"">
		|               <xsl:with-param name=""str"" select=""substring-after(., '=')"" />
		|               <xsl:with-param name=""search-for"" select=""'&#13;'"" />
		|               <xsl:with-param name=""replace-by"" select=""'&#10;'"" />
		|             </xsl:call-template>
		|           </Value>
		|
		|         </xsl:element>
		|
		|       </xsl:if>
		|     </xsl:for-each>
		|
		|    </Structure>
		|
		|  </xsl:template>
		|
		|</xsl:stylesheet>
		|");

	Возврат Преобразователь;
КонецФункции

Функция ПреобразованиеXSLT_СписокЗначенийВСтруктуру()
	Преобразователь = Новый ПреобразованиеXSL;
	Преобразователь.ЗагрузитьТаблицуСтилейXSLИзСтроки("
		|<xsl:stylesheet version=""1.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform""
		|  xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""
		|  xmlns:tns=""http://v8.1c.ru/8.1/data/core""
		|  xmlns=""http://v8.1c.ru/8.1/data/core""
		|>
		|<xsl:output method=""xml"" omit-xml-declaration=""yes"" indent=""yes"" encoding=""utf-8""/>
		|" + XSLT_ШаблоныСтроковыхФункций() + "
		|
		|  <xsl:template match=""/"">
		|    <Structure xmlns=""http://v8.1c.ru/8.1/data/core"" xmlns:xs=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xsi:type=""Structure"">
		|      <xsl:apply-templates select=""//tns:ValueListType/tns:item"" />
		|    </Structure >
		|  </xsl:template>
		|
		|  <xsl:template match=""//tns:ValueListType/tns:item"">
		|    <xsl:element name=""Property"">
		|      <xsl:attribute name=""name"">
		|        <xsl:call-template name=""str-trim-all"">
		|          <xsl:with-param name=""str"" select=""tns:presentation"" />
		|        </xsl:call-template>
		|      </xsl:attribute>
		|
		|      <xsl:element name=""Value"">
		|        <xsl:attribute name=""xsi:type"">
		|          <xsl:value-of select=""tns:value/@xsi:type""/>  
		|        </xsl:attribute>
		|        <xsl:value-of select=""tns:value""/>  
		|      </xsl:element>
		|
		|    </xsl:element>
		|</xsl:template>
		|
		|</xsl:stylesheet>
		|");
	Возврат Преобразователь;
КонецФункции

Функция ПреобразованиеXSLT_СоответствиеВСтруктуру()
	Преобразователь = Новый ПреобразованиеXSL;
	Преобразователь.ЗагрузитьТаблицуСтилейXSLИзСтроки("
		|<xsl:stylesheet version=""1.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform""
		|  xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""
		|  xmlns:tns=""http://v8.1c.ru/8.1/data/core""
		|  xmlns=""http://v8.1c.ru/8.1/data/core""
		|>
		|<xsl:output method=""xml"" omit-xml-declaration=""yes"" indent=""yes"" encoding=""utf-8""/>
		|" + XSLT_ШаблоныСтроковыхФункций() + "
		|
		|  <xsl:template match=""/"">
		|    <Structure xmlns=""http://v8.1c.ru/8.1/data/core"" xmlns:xs=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xsi:type=""Structure"">
		|      <xsl:apply-templates select=""//tns:Map/tns:pair"" />
		|    </Structure >
		|  </xsl:template>
		|  
		|  <xsl:template match=""//tns:Map/tns:pair"">
		|  <xsl:element name=""Property"">
		|    <xsl:attribute name=""name"">
		|      <xsl:call-template name=""str-trim-all"">
		|        <xsl:with-param name=""str"" select=""tns:Key"" />
		|      </xsl:call-template>
		|    </xsl:attribute>
		|  
		|    <xsl:element name=""Value"">
		|      <xsl:attribute name=""xsi:type"">
		|        <xsl:value-of select=""tns:Value/@xsi:type""/>  
		|      </xsl:attribute>
		|        <xsl:value-of select=""tns:Value""/>  
		|      </xsl:element>
		|  
		|    </xsl:element>
		|  </xsl:template>
		|
		|</xsl:stylesheet>
		|");
	Возврат Преобразователь;
КонецФункции

Функция ПреобразованиеXSLT_УдалитьОписаниеXML()
	Преобразователь = Новый ПреобразованиеXSL;
	Преобразователь.ЗагрузитьТаблицуСтилейXSLИзСтроки("
		|<xsl:stylesheet version=""1.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform"">
		|<xsl:output method=""xml"" omit-xml-declaration=""yes"" indent=""yes"" encoding=""utf-8""/>
		|  <xsl:template match=""node() | @*"">
		|    <xsl:copy>
		|      <xsl:apply-templates select=""node() | @*"" />
		|    </xsl:copy>
		|  </xsl:template>
		|</xsl:stylesheet>
		|");
	Возврат Преобразователь;
КонецФункции

Функция ПреобразованиеXSLT_ТипКонтактнойИнформацииПоСтрокеXML()
	
	Преобразователь = Новый ПреобразованиеXSL;
	
	Шаблон = "
		|<xsl:stylesheet version=""1.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform""
		|  xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""
		|  xmlns:ci=""http://www.v8.1c.ru/ssl/contactinfo""
		|>
		|  <xsl:output method=""xml"" omit-xml-declaration=""yes"" indent=""yes"" encoding=""utf-8""/>
		|
		|  <xsl:template match=""/"">
		|    <EnumRef.ТипыКонтактнойИнформации xmlns=""http://v8.1c.ru/8.1/data/enterprise/current-config"" xmlns:xs=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xsi:type=""EnumRef.ТипыКонтактнойИнформации"">
		|      <xsl:call-template name=""enum-by-type"" >
		|        <xsl:with-param name=""type"" select=""ci:[КонтактнаяИнформация]/ci:[Состав]/@xsi:type"" />
		|      </xsl:call-template>
		|    </EnumRef.ТипыКонтактнойИнформации>
		|  </xsl:template>
		|
		|  <xsl:template name=""enum-by-type"">
		|    <xsl:param name=""type"" />
		|    <xsl:choose>
		|      <xsl:when test=""$type='[Адрес]'"">
		|        <xsl:text>Адрес</xsl:text>
		|      </xsl:when>
		|      <xsl:when test=""$type='[НомерТелефона]'"">
		|        <xsl:text>Телефон</xsl:text>
		|      </xsl:when>
		|      <xsl:when test=""$type='[НомерФакса]'"">
		|        <xsl:text>Факс</xsl:text>
		|      </xsl:when>
		|      <xsl:when test=""$type='[ЭлектроннаяПочта]'"">
		|        <xsl:text>АдресЭлектроннойПочты</xsl:text>
		|      </xsl:when>
		|      <xsl:when test=""$type='[ВебСайт]'"">
		|        <xsl:text>ВебСтраница</xsl:text>
		|      </xsl:when>
		|      <xsl:when test=""$type='[Прочее]'"">
		|        <xsl:text>Другое</xsl:text>
		|      </xsl:when>
		|    </xsl:choose>
		|  </xsl:template>
		|
		|</xsl:stylesheet>
		|";
		
		ИменаСвойствXDTOПакета = Новый Структура();
		
		ИменаСвойствXDTOПакета.Вставить("КонтактнаяИнформация", "КонтактнаяИнформация"); // @Non-NLS-2
		ИменаСвойствXDTOПакета.Вставить("Состав", "Состав"); // @Non-NLS-2
		ИменаСвойствXDTOПакета.Вставить("Адрес", "Адрес"); // @Non-NLS-2
		ИменаСвойствXDTOПакета.Вставить("НомерТелефона", "НомерТелефона"); // @Non-NLS-2
		ИменаСвойствXDTOПакета.Вставить("НомерФакса", "НомерФакса"); // @Non-NLS-2
		ИменаСвойствXDTOПакета.Вставить("ЭлектроннаяПочта", "ЭлектроннаяПочта"); // @Non-NLS-2
		ИменаСвойствXDTOПакета.Вставить("ВебСайт", "ВебСайт"); // @Non-NLS-2
		ИменаСвойствXDTOПакета.Вставить("Прочее", "Прочее"); // @Non-NLS-2
		
		Шаблон = СтроковыеФункцииКлиентСервер.ВставитьПараметрыВСтроку(Шаблон, ИменаСвойствXDTOПакета);
		
		Преобразователь.ЗагрузитьТаблицуСтилейXSLИзСтроки(Шаблон);
		
	Возврат Преобразователь;
КонецФункции

// Описание
// 
// Параметры:
//   ТипКонтактнойИнформации - ПеречислениеСсылка.ТипыКонтактнойИнформации
// Возвращаемое значение:
//   ПреобразованиеXSL - Описание
// 
Функция ПреобразованиеXSLT_ИнтерпретацияРазличияXMLКонтактнойИнформации(Знач ТипКонтактнойИнформации)
	
	Если ТипЗнч(ТипКонтактнойИнформации) <> Тип("Строка") Тогда
		ТипКонтактнойИнформации = ТипКонтактнойИнформации.Метаданные().Имя;
	КонецЕсли;
	
	Преобразователь = Новый ПреобразованиеXSL;
	Преобразователь.ЗагрузитьТаблицуСтилейXSLИзСтроки("
		|<xsl:stylesheet version=""1.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform""
		|  xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""
		|  xmlns:ci=""http://www.v8.1c.ru/ssl/contactinfo""
		|>
		|<xsl:output method=""xml"" omit-xml-declaration=""yes"" indent=""yes"" encoding=""utf-8""/>
		|  <xsl:param name=""target-type"" select=""'" + ТипКонтактнойИнформации + "'""/>
		|
		|  <xsl:template match=""/"">
		|    <xsl:choose>
		|      <xsl:when test=""$target-type='Адрес'"">
		|         <xsl:apply-templates select=""."" mode=""action-address""/>
		|      </xsl:when>
		|      <xsl:otherwise>
		|         <xsl:apply-templates select=""."" mode=""action-copy""/>
		|      </xsl:otherwise>
		|    </xsl:choose>
		|  </xsl:template>
		|
		|  <xsl:template match=""node() | @*"" mode=""action-copy"">
		|    <xsl:copy>
		|      <xsl:apply-templates select=""node() | @*"" mode=""action-copy""/>
		|    </xsl:copy>
		|  </xsl:template>
		|
		|  <xsl:template match=""node() | @*"" mode=""action-address"">
		|    <xsl:copy>
		|      <xsl:apply-templates select=""node() | @*"" mode=""action-address""/>
		|    </xsl:copy>
		|  </xsl:template>
		|
		|</xsl:stylesheet>
		|");
	Возврат Преобразователь;
КонецФункции

Функция ПреобразованиеXSLT_ПреобразованиеXSL()
	
	Если УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ДоступныМодулиРаботаСАдресами() Тогда
		МодульРаботаСАдресами = ОбщегоНазначения.ОбщийМодуль("РаботаСАдресами");
		ДополнительныеПравилаПреобразования = МодульРаботаСАдресами.ДополнительныеПравилаПреобразования();
	КонецЕсли;
	
	ОсновнаяСтрана = "";
	Если УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ДоступныМодулиРаботаСАдресами() Тогда
		МодульРаботаСАдресамиКлиентСервер = ОбщегоНазначения.ОбщийМодуль("РаботаСАдресамиКлиентСервер");
		ОсновнаяСтрана = МодульРаботаСАдресамиКлиентСервер.ОсновнаяСтрана();
	КонецЕсли;
	
	Преобразователь = Новый ПреобразованиеXSL;
	Преобразователь.ЗагрузитьТаблицуСтилейXSLИзСтроки("
		|<xsl:stylesheet version=""1.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform""
		|  xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""
		|  xmlns:xs=""http://www.w3.org/2001/XMLSchema""
		|  xmlns:tns=""http://v8.1c.ru/8.1/data/core""
		|  xmlns=""http://www.v8.1c.ru/ssl/contactinfo"" 
		|
		|  xmlns:data=""http://www.v8.1c.ru/ssl/contactinfo""
		|
		|  xmlns:exsl=""http://exslt.org/common""
		|  extension-element-prefixes=""exsl""
		|  exclude-result-prefixes=""data tns""
		|>
		|<xsl:output method=""xml"" omit-xml-declaration=""yes"" indent=""yes"" encoding=""utf-8""/>
		|  " + XSLT_ШаблоныСтроковыхФункций() + "
		|  
		|  <xsl:variable name=""local-country"">" + ОсновнаяСтрана + "</xsl:variable>
		|
		|  <xsl:variable name=""presentation"" select=""tns:Structure/tns:Property[@name='Представление']/tns:Value/text()"" />
		|  
		|  <xsl:template match=""/"">
		|    <КонтактнаяИнформация>
		|
		|      <xsl:attribute name=""Представление"">
		|        <xsl:value-of select=""$presentation""/>
		|      </xsl:attribute> 
		|      <xsl:element name=""Комментарий"">
		|       <xsl:value-of select=""tns:Structure/tns:Property[@name='Комментарий']/tns:Value/text()""/>
		|      </xsl:element>
		|
		|      <xsl:element name=""Состав"">
		|        <xsl:attribute name=""xsi:type"">Адрес</xsl:attribute>
		|        <xsl:variable name=""country"" select=""tns:Structure/tns:Property[@name='Страна']/tns:Value/text()""></xsl:variable>
		|        <xsl:variable name=""country-upper"">
		|          <xsl:call-template name=""str-upper"">
		|            <xsl:with-param name=""str"" select=""$country"" />
		|          </xsl:call-template>
		|        </xsl:variable>
		|
		|        <xsl:attribute name=""Страна"">
		|          <xsl:choose>
		|            <xsl:when test=""0=count($country)"">
		|              <xsl:value-of select=""$local-country"" />
		|            </xsl:when>
		|            <xsl:otherwise>
		|              <xsl:value-of select=""$country"" />
		|            </xsl:otherwise> 
		|          </xsl:choose>
		|        </xsl:attribute>
		|
		|        <xsl:choose>
		|          <xsl:when test=""0=count($country)"">
		|            <xsl:apply-templates select=""/"" mode=""domestic"" />
		|          </xsl:when>
		|          <xsl:when test=""$country-upper=$local-country"">
		|            <xsl:apply-templates select=""/"" mode=""domestic"" />
		|          </xsl:when>
		|          <xsl:otherwise>
		|            <xsl:apply-templates select=""/"" mode=""foreign"" />
		|          </xsl:otherwise> 
		|        </xsl:choose>
		|
		|      </xsl:element>
		|    </КонтактнаяИнформация>
		|  </xsl:template>
		|  
		|  <xsl:template match=""/"" mode=""foreign"">
		|    <xsl:element name=""Состав"">
		|      <xsl:attribute name=""xsi:type"">xs:string</xsl:attribute>
		|
		|      <xsl:variable name=""value"" select=""tns:Structure/tns:Property[@name='Значение']/tns:Value/text()"" />        
		|      <xsl:choose>
		|        <xsl:when test=""0=count($value)"">
		|          <xsl:value-of select=""$presentation"" />
		|        </xsl:when>
		|        <xsl:otherwise>
		|          <xsl:value-of select=""$value"" />
		|        </xsl:otherwise> 
		|      </xsl:choose>
		|    
		|    </xsl:element>
		|  </xsl:template>
		|" + ДополнительныеПравилаПреобразования);
		
		Возврат Преобразователь;
КонецФункции

Функция ПреобразованиеXSLT_СтруктураВАдресЭлектроннойПочты()
	Возврат ПреобразованиеXSLT_СтруктураВСтроковыйСостав("ЭлектроннаяПочта");
КонецФункции

Функция ПреобразованиеXSLT_СтруктураВВебСтраницу()
	Возврат ПреобразованиеXSLT_СтруктураВСтроковыйСостав("ВебСайт");
КонецФункции

Функция ПреобразованиеXSLT_СтруктураВТелефон()
	Возврат ПреобразованиеXSLT_СтруктураВТелефонФакс("НомерТелефона");
КонецФункции

Функция ПреобразованиеXSLT_СтруктураВФакс()
	Возврат ПреобразованиеXSLT_СтруктураВТелефонФакс("НомерФакса");
КонецФункции

Функция ПреобразованиеXSLT_СтруктураВДругое()
	Возврат ПреобразованиеXSLT_СтруктураВСтроковыйСостав("Прочее");
КонецФункции

Функция ПреобразованиеXSLT_СтруктураВСтроковыйСостав(Знач ИмяXDTOТипа)
	Преобразователь = Новый ПреобразованиеXSL;
	Преобразователь.ЗагрузитьТаблицуСтилейXSLИзСтроки("
		|<xsl:stylesheet version=""1.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform""
		|  xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""
		|  xmlns:tns=""http://v8.1c.ru/8.1/data/core""
		|  xmlns=""http://www.v8.1c.ru/ssl/contactinfo"" 
		|>
		|<xsl:output method=""xml"" omit-xml-declaration=""yes"" indent=""yes"" encoding=""utf-8""/>
		|
		|<xsl:template match=""/"">
		|  
		|  <xsl:element name=""КонтактнаяИнформация"">
		|  
		|  <xsl:attribute name=""Представление"">
		|    <xsl:value-of select=""tns:Structure/tns:Property[@name='Представление']/tns:Value/text()""/>
		|  </xsl:attribute> 
		|  <xsl:element name=""Комментарий"">
		|    <xsl:value-of select=""tns:Structure/tns:Property[@name='Комментарий']/tns:Value/text()""/>
		|  </xsl:element>
		|  
		|  <xsl:element name=""Состав"">
		|    <xsl:attribute name=""xsi:type"">" + ИмяXDTOТипа + "</xsl:attribute>
		|    <xsl:attribute name=""Значение"">
		|    <xsl:choose>
		|      <xsl:when test=""0=count(tns:Structure/tns:Property[@name='Значение'])"">
		|      <xsl:value-of select=""tns:Structure/tns:Property[@name='Представление']/tns:Value/text()""/>
		|      </xsl:when>
		|      <xsl:otherwise>
		|      <xsl:value-of select=""tns:Structure/tns:Property[@name='Значение']/tns:Value/text()""/>
		|      </xsl:otherwise>
		|    </xsl:choose>
		|    </xsl:attribute>
		|    
		|  </xsl:element>
		|  </xsl:element>
		|  
		|</xsl:template>
		|</xsl:stylesheet>
		|");
	Возврат Преобразователь;
КонецФункции

Функция ПреобразованиеXSLT_СтруктураВТелефонФакс(Знач ИмяXDTOТипа)
	Преобразователь = Новый ПреобразованиеXSL;
	Преобразователь.ЗагрузитьТаблицуСтилейXSLИзСтроки("
		|<xsl:stylesheet version=""1.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform""
		|  xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""
		|  xmlns:tns=""http://v8.1c.ru/8.1/data/core""
		|  xmlns=""http://www.v8.1c.ru/ssl/contactinfo"" 
		|>
		|<xsl:output method=""xml"" omit-xml-declaration=""yes"" indent=""yes"" encoding=""utf-8""/>
		|  <xsl:template match=""/"">
		|
		|    <xsl:element name=""КонтактнаяИнформация"">
		|
		|      <xsl:attribute name=""Представление"">
		|        <xsl:value-of select=""tns:Structure/tns:Property[@name='Представление']/tns:Value/text()""/>
		|      </xsl:attribute> 
		|      <xsl:element name=""Комментарий"">
		|        <xsl:value-of select=""tns:Structure/tns:Property[@name='Комментарий']/tns:Value/text()""/>
		|      </xsl:element>
		|      <xsl:element name=""Состав"">
		|        <xsl:attribute name=""xsi:type"">" + ИмяXDTOТипа + "</xsl:attribute>
		|
		|        <xsl:attribute name=""КодСтраны"">
		|          <xsl:value-of select=""tns:Structure/tns:Property[@name='КодСтраны']/tns:Value/text()""/>
		|        </xsl:attribute> 
		|        <xsl:attribute name=""КодГорода"">
		|          <xsl:value-of select=""tns:Structure/tns:Property[@name='КодГорода']/tns:Value/text()""/>
		|        </xsl:attribute> 
		|        <xsl:attribute name=""Номер"">
		|          <xsl:value-of select=""tns:Structure/tns:Property[@name='НомерТелефона']/tns:Value/text()""/>
		|        </xsl:attribute> 
		|        <xsl:attribute name=""Добавочный"">
		|          <xsl:value-of select=""tns:Structure/tns:Property[@name='Добавочный']/tns:Value/text()""/>
		|        </xsl:attribute> 
		|
		|      </xsl:element>
		|    </xsl:element>
		|
		|  </xsl:template>
		|</xsl:stylesheet>
		|");
	Возврат Преобразователь;
КонецФункции

Функция XSLT_ШаблоныСтроковыхФункций()
	
	НаборБуквНижнийРегистр  = "abcdefghijklmnopqrstuvwxyz";
	НаборБуквВерхнийРегистр = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	
	Если УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ДоступныМодулиРаботаСАдресами() Тогда
		МодульРаботаСАдресами = ОбщегоНазначения.ОбщийМодуль("РаботаСАдресами");
		НаборБуквНижнийРегистр  = МодульРаботаСАдресами.НаборБуквВНижнемРегистре();
		НаборБуквВерхнийРегистр = МодульРаботаСАдресами.НаборБуквВВерхнемРегистре();
	КонецЕсли;
	
	Возврат "
		|<!-- string functions -->
		|
		|  <xsl:template name=""str-trim-left"">
		|    <xsl:param name=""str"" />
		|    <xsl:variable name=""head"" select=""substring($str, 1, 1)""/>
		|    <xsl:variable name=""tail"" select=""substring($str, 2)""/>
		|    <xsl:choose>
		|      <xsl:when test=""(string-length($str) > 0) and (string-length(normalize-space($head)) = 0)"">
		|        <xsl:call-template name=""str-trim-left"">
		|          <xsl:with-param name=""str"" select=""$tail""/>
		|        </xsl:call-template>
		|      </xsl:when>
		|      <xsl:otherwise>
		|        <xsl:value-of select=""$str""/>
		|      </xsl:otherwise>
		|    </xsl:choose>
		|  </xsl:template>
		|
		|  <xsl:template name=""str-trim-right"">
		|    <xsl:param name=""str"" />
		|    <xsl:variable name=""head"" select=""substring($str, 1, string-length($str) - 1)""/>
		|    <xsl:variable name=""tail"" select=""substring($str, string-length($str))""/>
		|    <xsl:choose>
		|      <xsl:when test=""(string-length($str) > 0) and (string-length(normalize-space($tail)) = 0)"">
		|        <xsl:call-template name=""str-trim-right"">
		|          <xsl:with-param name=""str"" select=""$head""/>
		|        </xsl:call-template>
		|      </xsl:when>
		|      <xsl:otherwise>
		|        <xsl:value-of select=""$str""/>
		|      </xsl:otherwise>
		|    </xsl:choose>
		|  </xsl:template>
		|
		|  <xsl:template name=""str-trim-all"">
		|    <xsl:param name=""str"" />
		|      <xsl:call-template name=""str-trim-right"">
		|        <xsl:with-param name=""str"">
		|          <xsl:call-template name=""str-trim-left"">
		|            <xsl:with-param name=""str"" select=""$str""/>
		|          </xsl:call-template>
		|      </xsl:with-param>
		|    </xsl:call-template>
		|  </xsl:template>
		|
		|  <xsl:template name=""str-replace-all"">
		|    <xsl:param name=""str"" />
		|    <xsl:param name=""search-for"" />
		|    <xsl:param name=""replace-by"" />
		|    <xsl:choose>
		|      <xsl:when test=""contains($str, $search-for)"">
		|        <xsl:value-of select=""substring-before($str, $search-for)"" />
		|        <xsl:value-of select=""$replace-by"" />
		|        <xsl:call-template name=""str-replace-all"">
		|          <xsl:with-param name=""str"" select=""substring-after($str, $search-for)"" />
		|          <xsl:with-param name=""search-for"" select=""$search-for"" />
		|          <xsl:with-param name=""replace-by"" select=""$replace-by"" />
		|        </xsl:call-template>
		|      </xsl:when>
		|      <xsl:otherwise>
		|        <xsl:value-of select=""$str"" />
		|      </xsl:otherwise>
		|    </xsl:choose>
		|  </xsl:template>
		|
		|  <xsl:param name=""alpha-low"" select=""'" + НаборБуквНижнийРегистр + "'"" />
		|  <xsl:param name=""alpha-up""  select=""'" + НаборБуквВерхнийРегистр + "'"" />
		|
		|  <xsl:template name=""str-upper"">
		|    <xsl:param name=""str"" />
		|    <xsl:value-of select=""translate($str, $alpha-low, $alpha-up)""/>
		|  </xsl:template>
		|
		|  <xsl:template name=""str-lower"">
		|    <xsl:param name=""str"" />
		|    <xsl:value-of select=""translate($str, alpha-up, $alpha-low)"" />
		|  </xsl:template>
		|
		|<!-- /string functions -->
		|";
КонецФункции

Функция XSLT_ШаблоныФункцийXPath()
	Возврат "
		|<!-- path functions -->
		|
		|  <xsl:template name=""build-path"">
		|  <xsl:variable name=""node"" select="".""/>
		|
		|    <xsl:for-each select=""$node | $node/ancestor-or-self::node()[..]"">
		|      <xsl:choose>
		|        <!-- element -->
		|        <xsl:when test=""self::*"">
		|            <xsl:value-of select=""'/'""/>
		|            <xsl:value-of select=""name()""/>
		|            <xsl:variable name=""thisPosition"" select=""count(preceding-sibling::*[name(current()) = name()])""/>
		|            <xsl:variable name=""numFollowing"" select=""count(following-sibling::*[name(current()) = name()])""/>
		|            <xsl:if test=""$thisPosition + $numFollowing > 0"">
		|              <xsl:value-of select=""concat('[', $thisPosition +1, ']')""/>
		|            </xsl:if>
		|        </xsl:when>
		|        <xsl:otherwise>
		|          <!-- not element -->
		|          <xsl:choose>
		|            <!-- attribute -->
		|            <xsl:when test=""count(. | ../@*) = count(../@*)"">
		|                <xsl:value-of select=""'/'""/>
		|                <xsl:value-of select=""concat('@',name())""/>
		|            </xsl:when>
		|            <!-- text- -->
		|            <xsl:when test=""self::text()"">
		|                <xsl:value-of select=""'/'""/>
		|                <xsl:value-of select=""'text()'""/>
		|                <xsl:variable name=""thisPosition"" select=""count(preceding-sibling::text())""/>
		|                <xsl:variable name=""numFollowing"" select=""count(following-sibling::text())""/>
		|                <xsl:if test=""$thisPosition + $numFollowing > 0""> 
		|                  <xsl:value-of select=""concat('[', $thisPosition +1, ']')""/>
		|                </xsl:if>
		|            </xsl:when>
		|            <!-- processing instruction -->
		|            <xsl:when test=""self::processing-instruction()"">
		|                <xsl:value-of select=""'/'""/>
		|                <xsl:value-of select=""'processing-instruction()'""/>
		|                <xsl:variable name=""thisPosition"" select=""count(preceding-sibling::processing-instruction())""/>
		|                <xsl:variable name=""numFollowing"" select=""count(following-sibling::processing-instruction())""/>
		|                <xsl:if test=""$thisPosition + $numFollowing > 0"">
		|                  <xsl:value-of select=""concat('[', $thisPosition +1, ']')""/>
		|                </xsl:if>
		|            </xsl:when>
		|            <!-- comment -->
		|            <xsl:when test=""self::comment()"">
		|                <xsl:value-of select=""'/'""/>
		|                <xsl:value-of select=""'comment()'""/>
		|                <xsl:variable name=""thisPosition"" select=""count(preceding-sibling::comment())""/>
		|                <xsl:variable name=""numFollowing"" select=""count(following-sibling::comment())""/>
		|                <xsl:if test=""$thisPosition + $numFollowing > 0"">
		|                  <xsl:value-of select=""concat('[', $thisPosition +1, ']')""/>
		|                </xsl:if>
		|            </xsl:when>
		|            <!-- namespace -->
		|            <xsl:when test=""count(. | ../namespace::*) = count(../namespace::*)"">
		|              <xsl:variable name=""ap"">'</xsl:variable>
		|              <xsl:value-of select=""'/'""/>
		|                <xsl:value-of select=""concat('namespace::*','[local-name() = ', $ap, local-name(), $ap, ']')""/>
		|            </xsl:when>
		|          </xsl:choose>
		|        </xsl:otherwise>
		|      </xsl:choose>
		|    </xsl:for-each>
		|
		|  </xsl:template>
		|
		|<!-- /path functions -->
		|";
КонецФункции

#КонецОбласти

#КонецОбласти
